diff --git a/.hgtags b/.hgtags index af2c1e3c0a5..261cb1ea200 100644 --- a/.hgtags +++ b/.hgtags @@ -195,3 +195,4 @@ adb5171c554e14cd86f618b5584f6e3d693d5889 jdk8-b69 a41ada2ed4ef735449531c6ebe6cec593d890a1c jdk8-b71 6725b3961f987cf40f446d1c11cd324a3bec545f jdk8-b72 fe94b40ffd9390f6cffcdf51c0389b0e6dde0c13 jdk8-b73 +f627eff819628822a0777af8062244352f2a29cf jdk8-b74 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 8555b3366ec..53096d3923b 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -195,3 +195,4 @@ cdb401a60cea6ad5ef3f498725ed1decf8dda1ea jdk8-b68 51ad2a34342055333eb5f36e2fb514b027895708 jdk8-b71 c1be681d80a1f1c848dc671d664fccb19e046a12 jdk8-b72 93b9664f97eeb6f89397a8842318ebacaac9feb9 jdk8-b73 +b43aa5bd8ca5c8121336495382d35ecfa7a71536 jdk8-b74 diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 2ab9711e3d3..2415b520802 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3723,7 +3723,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1358499442 +DATE_WHEN_GENERATED=1359376859 ############################################################################### # diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index d9f188d65d8..48eb3f85c0e 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -389,7 +389,8 @@ if test "x$with_milestone" = xyes; then AC_MSG_ERROR([Milestone must have a value]) elif test "x$with_milestone" != x; then MILESTONE="$with_milestone" -else +fi +if test "x$MILESTONE" = x; then MILESTONE=internal fi diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index e1fea0726d6..91b0a846e5f 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -136,6 +136,12 @@ fi AC_PATH_X AC_PATH_XTRA +# AC_PATH_XTRA creates X_LIBS and sometimes adds -R flags. When cross compiling +# this doesn't make sense so we remove it. +if test "x$COMPILE_TYPE" = xcross; then + X_LIBS=`$ECHO $X_LIBS | $SED 's/-R \{0,1\}[[^ ]]*//g'` +fi + if test "x$no_x" = xyes && test "x$X11_NOT_NEEDED" != xyes; then HELP_MSG_MISSING_DEPENDENCY([x11]) AC_MSG_ERROR([Could not find X11 libraries. $HELP_MSG]) diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 1e1ceb08ae6..0ba46727acc 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -350,9 +350,15 @@ compare_zip_file() { OTHER_DIR=$2 WORK_DIR=$3 ZIP_FILE=$4 + # Optionally provide different name for other zipfile + OTHER_ZIP_FILE=$5 THIS_ZIP=$THIS_DIR/$ZIP_FILE - OTHER_ZIP=$OTHER_DIR/$ZIP_FILE + if [ -n "$OTHER_ZIP_FILE" ]; then + OTHER_ZIP=$OTHER_DIR/$OTHER_ZIP_FILE + else + OTHER_ZIP=$OTHER_DIR/$ZIP_FILE + fi THIS_SUFFIX="${THIS_ZIP##*.}" OTHER_SUFFIX="${OTHER_ZIP##*.}" @@ -962,6 +968,9 @@ if [ -z "$1" ] || [ "$1" = "-h" ] || [ "$1" = "-?" ] || [ "$1" = "/h" ] || [ "$1 echo "[FILTER] List filenames in the image to compare, works for jars, zips, libs and execs" echo "Example:" echo "bash ./common/bin/compareimages.sh CodePointIM.jar" + echo "" + echo "-2zips Compare two zip files only" + echo "" exit 10 fi @@ -1023,6 +1032,13 @@ while [ -n "$1" ]; do -execs) CMP_EXECS=true ;; + -2zips) + CMP_2_ZIPS=true + THIS_FILE=$2 + OTHER_FILE=$3 + shift + shift + ;; *) CMP_NAMES=false CMP_PERMS=false @@ -1041,6 +1057,18 @@ while [ -n "$1" ]; do shift done +if [ "$CMP_2_ZIPS" = "true" ]; then + THIS_DIR="$(dirname $THIS_FILE)" + THIS_DIR="$(cd "$THIS_DIR" && pwd )" + OTHER_DIR="$(dirname $OTHER_FILE)" + OTHER_DIR="$(cd "$OTHER_DIR" && pwd )" + THIS_FILE_NAME="$(basename $THIS_FILE)" + OTHER_FILE_NAME="$(basename $OTHER_FILE)" + echo Comparing $THIS_DIR/$THIS_FILE_NAME and $OTHER_DIR/$OTHER_FILE_NAME + compare_zip_file $THIS_DIR $OTHER_DIR $COMPARE_ROOT/2zips $THIS_FILE_NAME $OTHER_FILE_NAME + exit +fi + if [ "$CMP_NAMES" = "false" ] && [ "$CMP_TYPES" = "false" ] && [ "$CMP_PERMS" = "false" ] && [ "$CMP_GENERAL" = "false" ] && [ "$CMP_ZIPS" = "false" ] && [ "$CMP_JARS" = "false" ] && [ "$CMP_LIBS" = "false" ] && [ "$CMP_EXECS" = "false" ]; then CMP_NAMES=true CMP_PERMS=true diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index 8b2b64dec24..3b79a526f56 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -887,6 +887,17 @@ ACCEPTED_SMALL_SIZE_DIFF=" ./jre/bin/unpack200.exe " +# jabswitch.exe is compiled and linked with incremental turned on in the old +# build. This makes no sense, so it's turned off in the new build. +ACCEPTED_SIZE_DIFF=" +./bin/jabswitch.exe +./jre/bin/jabswitch.exe +" +ACCEPTED_DIS_DIFF=" +./bin/jabswitch.exe +./jre/bin/jabswitch.exe +" + # On windows, there are unavoidable allignment issues making # a perfect disasm diff impossible. Filter out the following: # * Random parts of C++ symbols (this is a bit greedy, but does the trick) diff --git a/common/makefiles/javadoc/CORE_PKGS.gmk b/common/makefiles/javadoc/CORE_PKGS.gmk index dcfda026ded..b91aae1b650 100644 --- a/common/makefiles/javadoc/CORE_PKGS.gmk +++ b/common/makefiles/javadoc/CORE_PKGS.gmk @@ -127,6 +127,11 @@ CORE_PKGS = \ java.sql \ java.text \ java.text.spi \ + java.time \ + java.time.temporal \ + java.time.calendar \ + java.time.format \ + java.time.zone \ java.util \ java.util.concurrent \ java.util.concurrent.atomic \ diff --git a/common/makefiles/javadoc/Javadoc.gmk b/common/makefiles/javadoc/Javadoc.gmk index cee44b958fe..6b88a06d748 100644 --- a/common/makefiles/javadoc/Javadoc.gmk +++ b/common/makefiles/javadoc/Javadoc.gmk @@ -1,4 +1,4 @@ -# 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 @@ -269,6 +269,7 @@ COMMON_JAVADOCFLAGS = \ -quiet \ -use \ -keywords \ + -Xdoclint:none \ $(ADDITIONAL_JAVADOCFLAGS) ifdef OPENJDK diff --git a/corba/.hgtags b/corba/.hgtags index 1a3ee17d1bb..c01bb26f197 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -195,3 +195,4 @@ d54dc53e223ed9ce7d5f4d2cd02ad9d5def3c2db jdk8-b59 8171d23e914d758836527b80b06debcfdb718f2d jdk8-b71 cb40427f47145b01b7e53c3e02b38ff7625efbda jdk8-b72 191afde59e7be0e1a1d76d06f2a32ff17444f0ec jdk8-b73 +2132845cf5f717ff5c240a2431c0c0e03e66e3a5 jdk8-b74 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 617e00e138a..d46eb646def 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -308,3 +308,6 @@ e94068d4ff52849c8aa0786a53a59b63d1312a39 jdk8-b70 d5cb5830f570d1304ea4b196dde672a291b55f29 jdk8-b72 1e129851479e4f5df439109fca2c7be1f1613522 hs25-b15 11619f33cd683c2f1d6ef72f1c6ff3dacf5a9f1c jdk8-b73 +70c89bd6b895a10d25ca70e08093c09ff2005fda hs25-b16 +1a3e54283c54aaa8b3437813e8507fbdc966e5b6 jdk8-b74 +b4391649e91ea8d37f66317a03d6d2573a93d10d hs25-b17 diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index ba07fa34800..cfa26eacdbd 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -52,6 +52,9 @@ public class InstanceKlass extends Klass { private static int LOW_OFFSET; private static int HIGH_OFFSET; private static int FIELD_SLOTS; + private static short FIELDINFO_TAG_SIZE; + private static short FIELDINFO_TAG_MASK; + private static short FIELDINFO_TAG_OFFSET; // ClassState constants private static int CLASS_STATE_ALLOCATED; @@ -96,9 +99,13 @@ public class InstanceKlass extends Klass { NAME_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::name_index_offset").intValue(); SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue(); INITVAL_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue(); - LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_offset").intValue(); - HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_offset").intValue(); + LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue(); + HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue(); FIELD_SLOTS = db.lookupIntConstant("FieldInfo::field_slots").intValue(); + FIELDINFO_TAG_SIZE = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue(); + FIELDINFO_TAG_MASK = db.lookupIntConstant("FIELDINFO_TAG_MASK").shortValue(); + FIELDINFO_TAG_OFFSET = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue(); + // read ClassState constants CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue(); CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue(); @@ -314,8 +321,12 @@ public class InstanceKlass extends Klass { public int getFieldOffset(int index) { U2Array fields = getFields(); - return VM.getVM().buildIntFromShorts(fields.at(index * FIELD_SLOTS + LOW_OFFSET), - fields.at(index * FIELD_SLOTS + HIGH_OFFSET)); + short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET); + short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET); + if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) { + return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE; + } + throw new RuntimeException("should not reach here"); } // Accessors for declared fields diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-debug b/hotspot/make/bsd/makefiles/mapfile-vers-debug index 00fd1892716..ef827302c54 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug @@ -3,7 +3,7 @@ # # -# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 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 @@ -205,7 +205,6 @@ SUNWprivate_1.1 { JVM_NewMultiArray; JVM_OnExit; JVM_Open; - JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-product b/hotspot/make/bsd/makefiles/mapfile-vers-product index dfa459f0316..0d2b04ca774 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product @@ -3,7 +3,7 @@ # # -# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 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 @@ -205,7 +205,6 @@ SUNWprivate_1.1 { JVM_NewMultiArray; JVM_OnExit; JVM_Open; - JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index d6959b3b86c..c47d3d18289 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2012 +HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=15 +HS_BUILD_NUMBER=17 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff --git a/hotspot/make/linux/makefiles/mapfile-vers-debug b/hotspot/make/linux/makefiles/mapfile-vers-debug index d6ebedcb9bd..ae4e2f9bcc3 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-debug +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 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 @@ -201,7 +201,6 @@ SUNWprivate_1.1 { JVM_NewMultiArray; JVM_OnExit; JVM_Open; - JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product index 733e3af4b11..9a3028d2a09 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-product +++ b/hotspot/make/linux/makefiles/mapfile-vers-product @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 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 @@ -201,7 +201,6 @@ SUNWprivate_1.1 { JVM_NewMultiArray; JVM_OnExit; JVM_Open; - JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; diff --git a/hotspot/make/solaris/makefiles/mapfile-vers b/hotspot/make/solaris/makefiles/mapfile-vers index a10d5c1b4e6..bf21253062e 100644 --- a/hotspot/make/solaris/makefiles/mapfile-vers +++ b/hotspot/make/solaris/makefiles/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2011, 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 @@ -201,7 +201,6 @@ SUNWprivate_1.1 { JVM_NewMultiArray; JVM_OnExit; JVM_Open; - JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; diff --git a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp index 8103a6395b7..11f829385b8 100644 --- a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp @@ -29,7 +29,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* JavaCallWrapper */ \ @@ -37,22 +37,12 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \ - \ + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */ - /* be present there) */ +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */ - /* be present there) */ - - -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ /******************************/ \ /* Register numbers (C2 only) */ \ /******************************/ \ @@ -90,15 +80,6 @@ declare_c2_constant(R_G6_num) \ declare_c2_constant(R_G7_num) - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ - -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // CPU_SPARC_VM_VMSTRUCTS_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 7d3becef336..03670106924 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -259,6 +259,10 @@ void VM_Version::initialize() { if (!has_vis1()) // Drop to 0 if no VIS1 support UseVIS = 0; + if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && + (cache_line_size > ContendedPaddingWidth)) + ContendedPaddingWidth = cache_line_size; + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print("Allocation"); @@ -286,6 +290,9 @@ void VM_Version::initialize() { if (PrefetchFieldsAhead > 0) { tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead); } + if (ContendedPaddingWidth > 0) { + tty->print_cr("ContendedPaddingWidth %d", ContendedPaddingWidth); + } } #endif // PRODUCT } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 8b474ba2409..795461d6abf 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2263,6 +2263,18 @@ void Assembler::packuswb(XMMRegister dst, XMMRegister src) { emit_simd_arith(0x67, dst, src, VEX_SIMD_66); } +void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { + assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); + emit_vex_arith(0x67, dst, nds, src, VEX_SIMD_66, vector256); +} + +void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256) { + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true, vector256); + emit_int8(0x00); + emit_int8(0xC0 | encode); + emit_int8(imm8); +} + void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); @@ -2475,7 +2487,7 @@ void Assembler::vptest(XMMRegister dst, Address src) { assert(dst != xnoreg, "sanity"); int dst_enc = dst->encoding(); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256); + vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256); emit_int8(0x17); emit_operand(dst, src); } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index bcef330e4cf..8dad416b09f 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1395,6 +1395,10 @@ private: // Pack with unsigned saturation void packuswb(XMMRegister dst, XMMRegister src); void packuswb(XMMRegister dst, Address src); + void vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256); + + // Pemutation of 64bit words + void vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256); // SSE4.2 string instructions void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); diff --git a/hotspot/src/cpu/x86/vm/jni_x86.h b/hotspot/src/cpu/x86/vm/jni_x86.h index d724c86007a..2cd7abd304e 100644 --- a/hotspot/src/cpu/x86/vm/jni_x86.h +++ b/hotspot/src/cpu/x86/vm/jni_x86.h @@ -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 @@ -38,14 +38,9 @@ #define JNICALL typedef int jint; -#if defined(_LP64) && !defined(__APPLE__) +#if defined(_LP64) typedef long jlong; #else - /* - * On _LP64 __APPLE__ "long" and "long long" are both 64 bits, - * but we use the "long long" typedef to avoid complaints from - * the __APPLE__ compiler about fprintf formats. - */ typedef long long jlong; #endif diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index e9e414077f5..e4b221b289b 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -6209,6 +6209,128 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, } BIND(L_exit); } + +// encode char[] to byte[] in ISO_8859_1 +void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, + XMMRegister tmp1Reg, XMMRegister tmp2Reg, + XMMRegister tmp3Reg, XMMRegister tmp4Reg, + Register tmp5, Register result) { + // rsi: src + // rdi: dst + // rdx: len + // rcx: tmp5 + // rax: result + ShortBranchVerifier sbv(this); + assert_different_registers(src, dst, len, tmp5, result); + Label L_done, L_copy_1_char, L_copy_1_char_exit; + + // set result + xorl(result, result); + // check for zero length + testl(len, len); + jcc(Assembler::zero, L_done); + movl(result, len); + + // Setup pointers + lea(src, Address(src, len, Address::times_2)); // char[] + lea(dst, Address(dst, len, Address::times_1)); // byte[] + negptr(len); + + if (UseSSE42Intrinsics || UseAVX >= 2) { + Label L_chars_8_check, L_copy_8_chars, L_copy_8_chars_exit; + Label L_chars_16_check, L_copy_16_chars, L_copy_16_chars_exit; + + if (UseAVX >= 2) { + Label L_chars_32_check, L_copy_32_chars, L_copy_32_chars_exit; + movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector + movdl(tmp1Reg, tmp5); + vpbroadcastd(tmp1Reg, tmp1Reg); + jmpb(L_chars_32_check); + + bind(L_copy_32_chars); + vmovdqu(tmp3Reg, Address(src, len, Address::times_2, -64)); + vmovdqu(tmp4Reg, Address(src, len, Address::times_2, -32)); + vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ true); + vptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector + jccb(Assembler::notZero, L_copy_32_chars_exit); + vpackuswb(tmp3Reg, tmp3Reg, tmp4Reg, /* vector256 */ true); + vpermq(tmp4Reg, tmp3Reg, 0xD8, /* vector256 */ true); + vmovdqu(Address(dst, len, Address::times_1, -32), tmp4Reg); + + bind(L_chars_32_check); + addptr(len, 32); + jccb(Assembler::lessEqual, L_copy_32_chars); + + bind(L_copy_32_chars_exit); + subptr(len, 16); + jccb(Assembler::greater, L_copy_16_chars_exit); + + } else if (UseSSE42Intrinsics) { + movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector + movdl(tmp1Reg, tmp5); + pshufd(tmp1Reg, tmp1Reg, 0); + jmpb(L_chars_16_check); + } + + bind(L_copy_16_chars); + if (UseAVX >= 2) { + vmovdqu(tmp2Reg, Address(src, len, Address::times_2, -32)); + vptest(tmp2Reg, tmp1Reg); + jccb(Assembler::notZero, L_copy_16_chars_exit); + vpackuswb(tmp2Reg, tmp2Reg, tmp1Reg, /* vector256 */ true); + vpermq(tmp3Reg, tmp2Reg, 0xD8, /* vector256 */ true); + } else { + if (UseAVX > 0) { + movdqu(tmp3Reg, Address(src, len, Address::times_2, -32)); + movdqu(tmp4Reg, Address(src, len, Address::times_2, -16)); + vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ false); + } else { + movdqu(tmp3Reg, Address(src, len, Address::times_2, -32)); + por(tmp2Reg, tmp3Reg); + movdqu(tmp4Reg, Address(src, len, Address::times_2, -16)); + por(tmp2Reg, tmp4Reg); + } + ptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector + jccb(Assembler::notZero, L_copy_16_chars_exit); + packuswb(tmp3Reg, tmp4Reg); + } + movdqu(Address(dst, len, Address::times_1, -16), tmp3Reg); + + bind(L_chars_16_check); + addptr(len, 16); + jccb(Assembler::lessEqual, L_copy_16_chars); + + bind(L_copy_16_chars_exit); + subptr(len, 8); + jccb(Assembler::greater, L_copy_8_chars_exit); + + bind(L_copy_8_chars); + movdqu(tmp3Reg, Address(src, len, Address::times_2, -16)); + ptest(tmp3Reg, tmp1Reg); + jccb(Assembler::notZero, L_copy_8_chars_exit); + packuswb(tmp3Reg, tmp1Reg); + movq(Address(dst, len, Address::times_1, -8), tmp3Reg); + addptr(len, 8); + jccb(Assembler::lessEqual, L_copy_8_chars); + + bind(L_copy_8_chars_exit); + subptr(len, 8); + jccb(Assembler::zero, L_done); + } + + bind(L_copy_1_char); + load_unsigned_short(tmp5, Address(src, len, Address::times_2, 0)); + testl(tmp5, 0xff00); // check if Unicode char + jccb(Assembler::notZero, L_copy_1_char_exit); + movb(Address(dst, len, Address::times_1, 0), tmp5); + addptr(len, 1); + jccb(Assembler::less, L_copy_1_char); + + bind(L_copy_1_char_exit); + addptr(result, len); // len is negative count of not processed elements + bind(L_done); +} + #undef BIND #undef BLOCK_COMMENT diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 3afcf23ebae..e4b89322b9d 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1135,6 +1135,10 @@ public: Register to, Register value, Register count, Register rtmp, XMMRegister xtmp); + void encode_iso_array(Register src, Register dst, Register len, + XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3, + XMMRegister tmp4, Register tmp5, Register result); + #undef VIRTUAL }; diff --git a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp index 8dddc9c3e1d..847d08ed207 100644 --- a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp @@ -29,7 +29,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* JavaCallWrapper */ \ @@ -37,31 +37,14 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ - \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */ - /* be present there) */ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */ - /* be present there) */ +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ - -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // CPU_X86_VM_VMSTRUCTS_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 75db2903b3e..90066c1041a 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -661,6 +661,14 @@ void VM_Version::get_processor_features() { } } } +#if defined(COMPILER2) && defined(_ALLBSD_SOURCE) + if (MaxVectorSize > 16) { + // Limit vectors size to 16 bytes on BSD until it fixes + // restoring upper 128bit of YMM registers on return + // from signal handler. + FLAG_SET_DEFAULT(MaxVectorSize, 16); + } +#endif // COMPILER2 // Use population count instruction if available. if (supports_popcnt()) { @@ -745,6 +753,10 @@ void VM_Version::get_processor_features() { PrefetchFieldsAhead = prefetch_fields_ahead(); #endif + if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && + (cache_line_size > ContendedPaddingWidth)) + ContendedPaddingWidth = cache_line_size; + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("Logical CPUs per core: %u", @@ -791,6 +803,9 @@ void VM_Version::get_processor_features() { if (PrefetchFieldsAhead > 0) { tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead); } + if (ContendedPaddingWidth > 0) { + tty->print_cr("ContendedPaddingWidth %d", ContendedPaddingWidth); + } } #endif // !PRODUCT } diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 462060de119..6ceb50cee84 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -11687,6 +11687,23 @@ instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI result, ins_pipe( pipe_slow ); %} +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(eSIRegP src, eDIRegP dst, eDXRegI len, + regD tmp1, regD tmp2, regD tmp3, regD tmp4, + eCXRegI tmp5, eAXRegI result, eFlagsReg cr) %{ + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register); + %} + ins_pipe( pipe_slow ); +%} + + //----------Control Flow Instructions------------------------------------------ // Signed compare Instructions instruct compI_eReg(eFlagsReg cr, rRegI op1, rRegI op2) %{ diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index b526a6ce27b..7c902c4e31c 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -10495,6 +10495,23 @@ instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, ins_pipe( pipe_slow ); %} +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, + regD tmp1, regD tmp2, regD tmp3, regD tmp4, + rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register); + %} + ins_pipe( pipe_slow ); +%} + + //----------Control Flow Instructions------------------------------------------ // Signed compare Instructions diff --git a/hotspot/src/cpu/zero/vm/frame_zero.cpp b/hotspot/src/cpu/zero/vm/frame_zero.cpp index 8643af5953f..56f2a7a1c71 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.cpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp @@ -98,10 +98,20 @@ BasicObjectLock* frame::interpreter_frame_monitor_end() const { #endif // CC_INTERP void frame::patch_pc(Thread* thread, address pc) { - // We borrow this call to set the thread pointer in the interpreter - // state; the hook to set up deoptimized frames isn't supplied it. - assert(pc == NULL, "should be"); - get_interpreterState()->set_thread((JavaThread *) thread); + + if (pc != NULL) { + _cb = CodeCache::find_blob(pc); + SharkFrame* sharkframe = zeroframe()->as_shark_frame(); + sharkframe->set_pc(pc); + _pc = pc; + _deopt_state = is_deoptimized; + + } else { + // We borrow this call to set the thread pointer in the interpreter + // state; the hook to set up deoptimized frames isn't supplied it. + assert(pc == NULL, "should be"); + get_interpreterState()->set_thread((JavaThread *) thread); + } } bool frame::safe_for_sender(JavaThread *thread) { diff --git a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp index 2bc703ae032..f6bd6d3c6be 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp @@ -45,27 +45,36 @@ inline frame::frame(ZeroFrame* zf, intptr_t* sp) { case ZeroFrame::ENTRY_FRAME: _pc = StubRoutines::call_stub_return_pc(); _cb = NULL; + _deopt_state = not_deoptimized; break; case ZeroFrame::INTERPRETER_FRAME: _pc = NULL; _cb = NULL; + _deopt_state = not_deoptimized; break; - case ZeroFrame::SHARK_FRAME: + case ZeroFrame::SHARK_FRAME: { _pc = zero_sharkframe()->pc(); _cb = CodeCache::find_blob_unsafe(pc()); + address original_pc = nmethod::get_deopt_original_pc(this); + if (original_pc != NULL) { + _pc = original_pc; + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } break; - + } case ZeroFrame::FAKE_STUB_FRAME: _pc = NULL; _cb = NULL; + _deopt_state = not_deoptimized; break; default: ShouldNotReachHere(); } - _deopt_state = not_deoptimized; } // Accessors diff --git a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp b/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp index 6c67d0eb1d8..505241b147f 100644 --- a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp +++ b/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp @@ -68,6 +68,10 @@ class SharkFrame : public ZeroFrame { return (address) value_of_word(pc_off); } + void set_pc(address pc) const { + *((address*) addr_of_word(pc_off)) = pc; + } + intptr_t* unextended_sp() const { return (intptr_t *) value_of_word(unextended_sp_off); } diff --git a/hotspot/src/cpu/zero/vm/vmStructs_zero.hpp b/hotspot/src/cpu/zero/vm/vmStructs_zero.hpp index 1b3815a0a2c..0bbc1f40f45 100644 --- a/hotspot/src/cpu/zero/vm/vmStructs_zero.hpp +++ b/hotspot/src/cpu/zero/vm/vmStructs_zero.hpp @@ -30,28 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */ - /* be present there) */ +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */ - /* be present there) */ - -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ - -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */ - /* be present there) */ +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // CPU_ZERO_VM_VMSTRUCTS_ZERO_HPP diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index db6f3e6a0ea..477b4923e02 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -243,29 +243,32 @@ void os::Bsd::initialize_system_info() { int mib[2]; size_t len; int cpu_val; - u_long mem_val; + julong mem_val; /* get processors count via hw.ncpus sysctl */ mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof(cpu_val); if (sysctl(mib, 2, &cpu_val, &len, NULL, 0) != -1 && cpu_val >= 1) { + assert(len == sizeof(cpu_val), "unexpected data size"); set_processor_count(cpu_val); } else { set_processor_count(1); // fallback } - /* get physical memory via hw.usermem sysctl (hw.usermem is used - * instead of hw.physmem because we need size of allocatable memory + /* get physical memory via hw.memsize sysctl (hw.memsize is used + * since it returns a 64 bit value) */ mib[0] = CTL_HW; - mib[1] = HW_USERMEM; + mib[1] = HW_MEMSIZE; len = sizeof(mem_val); - if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1) + if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1) { + assert(len == sizeof(mem_val), "unexpected data size"); _physical_memory = mem_val; - else + } else { _physical_memory = 256*1024*1024; // fallback (XXXBSD?) + } #ifdef __OpenBSD__ { @@ -4091,11 +4094,12 @@ void os::PlatformEvent::park() { // AKA "down()" } -- _nParked ; - // In theory we could move the ST of 0 into _Event past the unlock(), - // but then we'd need a MEMBAR after the ST. _Event = 0 ; status = pthread_mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); } guarantee (_Event >= 0, "invariant") ; } @@ -4158,40 +4162,44 @@ int os::PlatformEvent::park(jlong millis) { status = pthread_mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); assert (_nParked == 0, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); return ret; } void os::PlatformEvent::unpark() { - int v, AnyWaiters ; - for (;;) { - v = _Event ; - if (v > 0) { - // The LD of _Event could have reordered or be satisfied - // by a read-aside from this processor's write buffer. - // To avoid problems execute a barrier and then - // ratify the value. - OrderAccess::fence() ; - if (_Event == v) return ; - continue ; - } - if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ; + // Transitions for _Event: + // 0 :=> 1 + // 1 :=> 1 + // -1 :=> either 0 or 1; must signal target thread + // That is, we can safely transition _Event from -1 to either + // 0 or 1. Forcing 1 is slightly more efficient for back-to-back + // unpark() calls. + // See also: "Semaphores in Plan 9" by Mullender & Cox + // + // Note: Forcing a transition from "-1" to "1" on an unpark() means + // that it will take two back-to-back park() calls for the owning + // thread to block. This has the benefit of forcing a spurious return + // from the first park() call after an unpark() call which will help + // shake out uses of park() and unpark() without condition variables. + + if (Atomic::xchg(1, &_Event) >= 0) return; + + // Wait for the thread associated with the event to vacate + int status = pthread_mutex_lock(_mutex); + assert_status(status == 0, status, "mutex_lock"); + int AnyWaiters = _nParked; + assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); + if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { + AnyWaiters = 0; + pthread_cond_signal(_cond); } - if (v < 0) { - // Wait for the thread associated with the event to vacate - int status = pthread_mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - AnyWaiters = _nParked ; - assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ; - if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { - AnyWaiters = 0 ; - pthread_cond_signal (_cond); - } - status = pthread_mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - if (AnyWaiters != 0) { - status = pthread_cond_signal(_cond); - assert_status(status == 0, status, "cond_signal"); - } + status = pthread_mutex_unlock(_mutex); + assert_status(status == 0, status, "mutex_unlock"); + if (AnyWaiters != 0) { + status = pthread_cond_signal(_cond); + assert_status(status == 0, status, "cond_signal"); } // Note that we signal() _after dropping the lock for "immortal" Events. @@ -4277,13 +4285,14 @@ static void unpackTime(struct timespec* absTime, bool isAbsolute, jlong time) { } void Parker::park(bool isAbsolute, jlong time) { + // Ideally we'd do something useful while spinning, such + // as calling unpackTime(). + // Optional fast-path check: // Return immediately if a permit is available. - if (_counter > 0) { - _counter = 0 ; - OrderAccess::fence(); - return ; - } + // We depend on Atomic::xchg() having full barrier semantics + // since we are doing a lock-free update to _counter. + if (Atomic::xchg(0, &_counter) > 0) return; Thread* thread = Thread::current(); assert(thread->is_Java_thread(), "Must be JavaThread"); @@ -4324,6 +4333,8 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0; status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. OrderAccess::fence(); return; } @@ -4360,12 +4371,14 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0 ; status = pthread_mutex_unlock(_mutex) ; assert_status(status == 0, status, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. + OrderAccess::fence(); + // If externally suspended while waiting, re-suspend if (jt->handle_special_suspend_equivalent_condition()) { jt->java_suspend_self(); } - - OrderAccess::fence(); } void Parker::unpark() { diff --git a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp index 6a7cdc08b5f..8fc3c2b0878 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp +++ b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -59,14 +59,6 @@ inline const char* os::path_separator() { return ":"; } -inline const char* os::jlong_format_specifier() { - return "%lld"; -} - -inline const char* os::julong_format_specifier() { - return "%llu"; -} - // File names are case-sensitive on windows only inline int os::file_name_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 8377294d20a..8ff3c786b8b 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -5001,11 +5001,12 @@ void os::PlatformEvent::park() { // AKA "down()" } -- _nParked ; - // In theory we could move the ST of 0 into _Event past the unlock(), - // but then we'd need a MEMBAR after the ST. _Event = 0 ; status = pthread_mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); } guarantee (_Event >= 0, "invariant") ; } @@ -5068,40 +5069,44 @@ int os::PlatformEvent::park(jlong millis) { status = pthread_mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); assert (_nParked == 0, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); return ret; } void os::PlatformEvent::unpark() { - int v, AnyWaiters ; - for (;;) { - v = _Event ; - if (v > 0) { - // The LD of _Event could have reordered or be satisfied - // by a read-aside from this processor's write buffer. - // To avoid problems execute a barrier and then - // ratify the value. - OrderAccess::fence() ; - if (_Event == v) return ; - continue ; - } - if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ; + // Transitions for _Event: + // 0 :=> 1 + // 1 :=> 1 + // -1 :=> either 0 or 1; must signal target thread + // That is, we can safely transition _Event from -1 to either + // 0 or 1. Forcing 1 is slightly more efficient for back-to-back + // unpark() calls. + // See also: "Semaphores in Plan 9" by Mullender & Cox + // + // Note: Forcing a transition from "-1" to "1" on an unpark() means + // that it will take two back-to-back park() calls for the owning + // thread to block. This has the benefit of forcing a spurious return + // from the first park() call after an unpark() call which will help + // shake out uses of park() and unpark() without condition variables. + + if (Atomic::xchg(1, &_Event) >= 0) return; + + // Wait for the thread associated with the event to vacate + int status = pthread_mutex_lock(_mutex); + assert_status(status == 0, status, "mutex_lock"); + int AnyWaiters = _nParked; + assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); + if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { + AnyWaiters = 0; + pthread_cond_signal(_cond); } - if (v < 0) { - // Wait for the thread associated with the event to vacate - int status = pthread_mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - AnyWaiters = _nParked ; - assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ; - if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { - AnyWaiters = 0 ; - pthread_cond_signal (_cond); - } - status = pthread_mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - if (AnyWaiters != 0) { - status = pthread_cond_signal(_cond); - assert_status(status == 0, status, "cond_signal"); - } + status = pthread_mutex_unlock(_mutex); + assert_status(status == 0, status, "mutex_unlock"); + if (AnyWaiters != 0) { + status = pthread_cond_signal(_cond); + assert_status(status == 0, status, "cond_signal"); } // Note that we signal() _after dropping the lock for "immortal" Events. @@ -5187,13 +5192,14 @@ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) { } void Parker::park(bool isAbsolute, jlong time) { + // Ideally we'd do something useful while spinning, such + // as calling unpackTime(). + // Optional fast-path check: // Return immediately if a permit is available. - if (_counter > 0) { - _counter = 0 ; - OrderAccess::fence(); - return ; - } + // We depend on Atomic::xchg() having full barrier semantics + // since we are doing a lock-free update to _counter. + if (Atomic::xchg(0, &_counter) > 0) return; Thread* thread = Thread::current(); assert(thread->is_Java_thread(), "Must be JavaThread"); @@ -5234,6 +5240,8 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0; status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. OrderAccess::fence(); return; } @@ -5270,12 +5278,14 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0 ; status = pthread_mutex_unlock(_mutex) ; assert_status(status == 0, status, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. + OrderAccess::fence(); + // If externally suspended while waiting, re-suspend if (jt->handle_special_suspend_equivalent_condition()) { jt->java_suspend_self(); } - - OrderAccess::fence(); } void Parker::unpark() { diff --git a/hotspot/src/os/linux/vm/os_linux.inline.hpp b/hotspot/src/os/linux/vm/os_linux.inline.hpp index c779f8a6aa5..3a8d8d97d9b 100644 --- a/hotspot/src/os/linux/vm/os_linux.inline.hpp +++ b/hotspot/src/os/linux/vm/os_linux.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -68,14 +68,6 @@ inline const char* os::path_separator() { return ":"; } -inline const char* os::jlong_format_specifier() { - return "%lld"; -} - -inline const char* os::julong_format_specifier() { - return "%llu"; -} - // File names are case-sensitive on windows only inline int os::file_name_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); diff --git a/hotspot/src/os/posix/launcher/java_md.c b/hotspot/src/os/posix/launcher/java_md.c index 970222c4fd3..b5fc949813c 100644 --- a/hotspot/src/os/posix/launcher/java_md.c +++ b/hotspot/src/os/posix/launcher/java_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -1876,11 +1876,6 @@ void SplashFreeLibrary() { } } -const char * -jlong_format_specifier() { - return "%lld"; -} - /* * Block current thread and continue execution in a new thread */ diff --git a/hotspot/src/os/posix/launcher/java_md.h b/hotspot/src/os/posix/launcher/java_md.h index ed36fd1af67..63c449a2926 100644 --- a/hotspot/src/os/posix/launcher/java_md.h +++ b/hotspot/src/os/posix/launcher/java_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -64,6 +64,12 @@ #define Counter2Micros(counts) (1) #endif /* HAVE_GETHRTIME */ +#ifdef _LP64 +#define JLONG_FORMAT "%ld" +#else +#define JLONG_FORMAT "%lld" +#endif + /* * Function prototypes. */ diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 41143af2d1a..389ed9aa294 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -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 @@ -6014,6 +6014,9 @@ void os::PlatformEvent::park() { // AKA: down() _Event = 0 ; status = os::Solaris::mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); } } @@ -6055,51 +6058,43 @@ int os::PlatformEvent::park(jlong millis) { _Event = 0 ; status = os::Solaris::mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock"); + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other. + OrderAccess::fence(); return ret; } void os::PlatformEvent::unpark() { - int v, AnyWaiters; + // Transitions for _Event: + // 0 :=> 1 + // 1 :=> 1 + // -1 :=> either 0 or 1; must signal target thread + // That is, we can safely transition _Event from -1 to either + // 0 or 1. Forcing 1 is slightly more efficient for back-to-back + // unpark() calls. + // See also: "Semaphores in Plan 9" by Mullender & Cox + // + // Note: Forcing a transition from "-1" to "1" on an unpark() means + // that it will take two back-to-back park() calls for the owning + // thread to block. This has the benefit of forcing a spurious return + // from the first park() call after an unpark() call which will help + // shake out uses of park() and unpark() without condition variables. - // Increment _Event. - // Another acceptable implementation would be to simply swap 1 - // into _Event: - // if (Swap (&_Event, 1) < 0) { - // mutex_lock (_mutex) ; AnyWaiters = nParked; mutex_unlock (_mutex) ; - // if (AnyWaiters) cond_signal (_cond) ; - // } - - for (;;) { - v = _Event ; - if (v > 0) { - // The LD of _Event could have reordered or be satisfied - // by a read-aside from this processor's write buffer. - // To avoid problems execute a barrier and then - // ratify the value. A degenerate CAS() would also work. - // Viz., CAS (v+0, &_Event, v) == v). - OrderAccess::fence() ; - if (_Event == v) return ; - continue ; - } - if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ; - } + if (Atomic::xchg(1, &_Event) >= 0) return; // If the thread associated with the event was parked, wake it. - if (v < 0) { - int status ; - // Wait for the thread assoc with the PlatformEvent to vacate. - status = os::Solaris::mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - AnyWaiters = _nParked ; - status = os::Solaris::mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - guarantee (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ; - if (AnyWaiters != 0) { - // We intentional signal *after* dropping the lock - // to avoid a common class of futile wakeups. - status = os::Solaris::cond_signal(_cond); - assert_status(status == 0, status, "cond_signal"); - } + // Wait for the thread assoc with the PlatformEvent to vacate. + int status = os::Solaris::mutex_lock(_mutex); + assert_status(status == 0, status, "mutex_lock"); + int AnyWaiters = _nParked; + status = os::Solaris::mutex_unlock(_mutex); + assert_status(status == 0, status, "mutex_unlock"); + guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); + if (AnyWaiters != 0) { + // We intentional signal *after* dropping the lock + // to avoid a common class of futile wakeups. + status = os::Solaris::cond_signal(_cond); + assert_status(status == 0, status, "cond_signal"); } } @@ -6177,14 +6172,14 @@ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) { } void Parker::park(bool isAbsolute, jlong time) { + // Ideally we'd do something useful while spinning, such + // as calling unpackTime(). // Optional fast-path check: // Return immediately if a permit is available. - if (_counter > 0) { - _counter = 0 ; - OrderAccess::fence(); - return ; - } + // We depend on Atomic::xchg() having full barrier semantics + // since we are doing a lock-free update to _counter. + if (Atomic::xchg(0, &_counter) > 0) return; // Optional fast-exit: Check interrupt before trying to wait Thread* thread = Thread::current(); @@ -6226,6 +6221,8 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0; status = os::Solaris::mutex_unlock(_mutex); assert (status == 0, "invariant") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. OrderAccess::fence(); return; } @@ -6267,12 +6264,14 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0 ; status = os::Solaris::mutex_unlock(_mutex); assert_status(status == 0, status, "mutex_unlock") ; + // Paranoia to ensure our locked and lock-free paths interact + // correctly with each other and Java-level accesses. + OrderAccess::fence(); // If externally suspended while waiting, re-suspend if (jt->handle_special_suspend_equivalent_condition()) { jt->java_suspend_self(); } - OrderAccess::fence(); } void Parker::unpark() { diff --git a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp index a3f09d01d32..61691fd384a 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp @@ -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 @@ -50,9 +50,6 @@ inline const char* os::file_separator() { return "/"; } inline const char* os::line_separator() { return "\n"; } inline const char* os::path_separator() { return ":"; } -inline const char* os::jlong_format_specifier() { return "%lld"; } -inline const char* os::julong_format_specifier() { return "%llu"; } - // File names are case-sensitive on windows only inline int os::file_name_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); diff --git a/hotspot/src/os/windows/launcher/java_md.c b/hotspot/src/os/windows/launcher/java_md.c index 2fde40ad205..3e28755009c 100644 --- a/hotspot/src/os/windows/launcher/java_md.c +++ b/hotspot/src/os/windows/launcher/java_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -1323,11 +1323,6 @@ void SplashFreeLibrary() { } } -const char * -jlong_format_specifier() { - return "%I64d"; -} - /* * Block current thread and continue execution in a new thread */ diff --git a/hotspot/src/os/windows/launcher/java_md.h b/hotspot/src/os/windows/launcher/java_md.h index 111be1ee13a..763e2457644 100644 --- a/hotspot/src/os/windows/launcher/java_md.h +++ b/hotspot/src/os/windows/launcher/java_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -69,6 +69,8 @@ extern jlong Counter2Micros(jlong counts); extern int _main(int argc, char **argv); #endif +#define JLONG_FORMAT "%I64d" + /* * Function prototypes. */ diff --git a/hotspot/src/os/windows/vm/decoder_windows.cpp b/hotspot/src/os/windows/vm/decoder_windows.cpp index 82ba909bc5c..2b4682728a2 100644 --- a/hotspot/src/os/windows/vm/decoder_windows.cpp +++ b/hotspot/src/os/windows/vm/decoder_windows.cpp @@ -49,7 +49,7 @@ void WindowsDecoder::initialize() { pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions"); pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize"); _pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64"); - _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)GetProcAddress(handle, "UnDecorateSymbolName"); + _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName"); if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) { _pfnSymGetSymFromAddr64 = NULL; @@ -60,8 +60,9 @@ void WindowsDecoder::initialize() { return; } - _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); - if (!_pfnSymInitialize(GetCurrentProcess(), NULL, TRUE)) { + HANDLE hProcess = ::GetCurrentProcess(); + _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); + if (!_pfnSymInitialize(hProcess, NULL, TRUE)) { _pfnSymGetSymFromAddr64 = NULL; _pfnUndecorateSymbolName = NULL; ::FreeLibrary(handle); @@ -70,6 +71,77 @@ void WindowsDecoder::initialize() { return; } + // set pdb search paths + pfn_SymSetSearchPath _pfn_SymSetSearchPath = + (pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath"); + pfn_SymGetSearchPath _pfn_SymGetSearchPath = + (pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath"); + if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) { + char paths[MAX_PATH]; + int len = sizeof(paths); + if (!_pfn_SymGetSearchPath(hProcess, paths, len)) { + paths[0] = '\0'; + } else { + // available spaces in path buffer + len -= (int)strlen(paths); + } + + char tmp_path[MAX_PATH]; + DWORD dwSize; + HMODULE hJVM = ::GetModuleHandle("jvm.dll"); + tmp_path[0] = '\0'; + // append the path where jvm.dll is located + if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) { + while (dwSize > 0 && tmp_path[dwSize] != '\\') { + dwSize --; + } + + tmp_path[dwSize] = '\0'; + + if (dwSize > 0 && len > (int)dwSize + 1) { + strncat(paths, os::path_separator(), 1); + strncat(paths, tmp_path, dwSize); + len -= dwSize + 1; + } + } + + // append $JRE/bin. Arguments::get_java_home actually returns $JRE + // path + char *p = Arguments::get_java_home(); + assert(p != NULL, "empty java home"); + size_t java_home_len = strlen(p); + if (len > (int)java_home_len + 5) { + strncat(paths, os::path_separator(), 1); + strncat(paths, p, java_home_len); + strncat(paths, "\\bin", 4); + len -= (int)(java_home_len + 5); + } + + // append $JDK/bin path if it exists + assert(java_home_len < MAX_PATH, "Invalid path length"); + // assume $JRE is under $JDK, construct $JDK/bin path and + // see if it exists or not + if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) { + strncpy(tmp_path, p, java_home_len - 3); + tmp_path[java_home_len - 3] = '\0'; + strncat(tmp_path, "bin", 3); + + // if the directory exists + DWORD dwAttrib = GetFileAttributes(tmp_path); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + // tmp_path should have the same length as java_home_len, since we only + // replaced 'jre' with 'bin' + if (len > (int)java_home_len + 1) { + strncat(paths, os::path_separator(), 1); + strncat(paths, tmp_path, java_home_len); + } + } + } + + _pfn_SymSetSearchPath(hProcess, paths); + } + // find out if jvm.dll contains private symbols, by decoding // current function and comparing the result address addr = (address)Decoder::demangle; diff --git a/hotspot/src/os/windows/vm/decoder_windows.hpp b/hotspot/src/os/windows/vm/decoder_windows.hpp index b2c2638d8ab..3008ee79136 100644 --- a/hotspot/src/os/windows/vm/decoder_windows.hpp +++ b/hotspot/src/os/windows/vm/decoder_windows.hpp @@ -35,6 +35,8 @@ typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD); typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL); typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD); +typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR); +typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int); class WindowsDecoder : public AbstractDecoder { diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index b8498d5a1e2..98b3077d1fa 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -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 @@ -1874,8 +1874,22 @@ static BOOL WINAPI consoleHandler(DWORD event) { } return TRUE; break; + case CTRL_LOGOFF_EVENT: { + // Don't terminate JVM if it is running in a non-interactive session, + // such as a service process. + USEROBJECTFLAGS flags; + HANDLE handle = GetProcessWindowStation(); + if (handle != NULL && + GetUserObjectInformation(handle, UOI_FLAGS, &flags, + sizeof( USEROBJECTFLAGS), NULL)) { + // If it is a non-interactive session, let next handler to deal + // with it. + if ((flags.dwFlags & WSF_VISIBLE) == 0) { + return FALSE; + } + } + } case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: os::signal_raise(SIGTERM); return TRUE; @@ -2946,7 +2960,7 @@ char* os::pd_reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { } if( Verbose && PrintMiscellaneous ) { reserveTimer.stop(); - tty->print_cr("reserve_memory of %Ix bytes took %ld ms (%ld ticks)", bytes, + tty->print_cr("reserve_memory of %Ix bytes took " JLONG_FORMAT " ms (" JLONG_FORMAT " ticks)", bytes, reserveTimer.milliseconds(), reserveTimer.ticks()); } } @@ -4305,7 +4319,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, if (hFile == NULL) { if (PrintMiscellaneous && Verbose) { DWORD err = GetLastError(); - tty->print_cr("CreateFile() failed: GetLastError->%ld."); + tty->print_cr("CreateFile() failed: GetLastError->%ld.", err); } return NULL; } @@ -4355,7 +4369,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, if (hMap == NULL) { if (PrintMiscellaneous && Verbose) { DWORD err = GetLastError(); - tty->print_cr("CreateFileMapping() failed: GetLastError->%ld."); + tty->print_cr("CreateFileMapping() failed: GetLastError->%ld.", err); } CloseHandle(hFile); return NULL; @@ -4565,6 +4579,7 @@ int os::PlatformEvent::park (jlong Millis) { } v = _Event ; _Event = 0 ; + // see comment at end of os::PlatformEvent::park() below: OrderAccess::fence() ; // If we encounter a nearly simultanous timeout expiry and unpark() // we return OS_OK indicating we awoke via unpark(). @@ -4602,25 +4617,25 @@ void os::PlatformEvent::park () { void os::PlatformEvent::unpark() { guarantee (_ParkHandle != NULL, "Invariant") ; - int v ; - for (;;) { - v = _Event ; // Increment _Event if it's < 1. - if (v > 0) { - // If it's already signaled just return. - // The LD of _Event could have reordered or be satisfied - // by a read-aside from this processor's write buffer. - // To avoid problems execute a barrier and then - // ratify the value. A degenerate CAS() would also work. - // Viz., CAS (v+0, &_Event, v) == v). - OrderAccess::fence() ; - if (_Event == v) return ; - continue ; - } - if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ; - } - if (v < 0) { - ::SetEvent (_ParkHandle) ; - } + + // Transitions for _Event: + // 0 :=> 1 + // 1 :=> 1 + // -1 :=> either 0 or 1; must signal target thread + // That is, we can safely transition _Event from -1 to either + // 0 or 1. Forcing 1 is slightly more efficient for back-to-back + // unpark() calls. + // See also: "Semaphores in Plan 9" by Mullender & Cox + // + // Note: Forcing a transition from "-1" to "1" on an unpark() means + // that it will take two back-to-back park() calls for the owning + // thread to block. This has the benefit of forcing a spurious return + // from the first park() call after an unpark() call which will help + // shake out uses of park() and unpark() without condition variables. + + if (Atomic::xchg(1, &_Event) >= 0) return; + + ::SetEvent(_ParkHandle); } diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/windows/vm/os_windows.inline.hpp index 8f8c3c72fd2..1df8694d9dd 100644 --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp @@ -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 @@ -38,9 +38,6 @@ inline const char* os::line_separator() { return "\r\n"; } inline const char* os::path_separator() { return ";"; } inline const char* os::dll_file_extension() { return ".dll"; } -inline const char* os::jlong_format_specifier() { return "%I64d"; } -inline const char* os::julong_format_specifier() { return "%I64u"; } - inline const int os::default_file_open_flags() { return O_BINARY | O_NOINHERIT;} // File names are case-insensitive on windows only diff --git a/hotspot/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp b/hotspot/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp index b98d975408a..edfbcfa9a54 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp @@ -29,37 +29,26 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) \ - /* This must be the last entry, and must be present */ \ - last_entry() + nonstatic_field(OSThread, _pthread_id, pthread_t) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ /* Posix Thread IDs */ \ /**********************/ \ \ declare_unsigned_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(pthread_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_BSD_X86_VM_VMSTRUCTS_BSD_X86_HPP diff --git a/hotspot/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp b/hotspot/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp index 17165cc9d13..6673f448f81 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp @@ -30,21 +30,13 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_BSD_ZERO_VM_VMSTRUCTS_BSD_ZERO_HPP diff --git a/hotspot/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp b/hotspot/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp index 58fc94bbc38..38bc63e6496 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp @@ -29,7 +29,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ @@ -37,38 +37,27 @@ \ nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) \ - /* This must be the last entry, and must be present */ \ - last_entry() + nonstatic_field(OSThread, _pthread_id, pthread_t) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ /* POSIX Thread IDs */ \ /**********************/ \ \ declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(pthread_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ \ /************************/ \ /* JavaThread constants */ \ /************************/ \ \ - declare_constant(JavaFrameAnchor::flushed) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_constant(JavaFrameAnchor::flushed) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_LINUX_SPARC_VM_VMSTRUCTS_LINUX_SPARC_HPP diff --git a/hotspot/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp b/hotspot/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp index c01e6c91c2a..828f992d8ba 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp @@ -29,37 +29,26 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) \ - /* This must be the last entry, and must be present */ \ - last_entry() + nonstatic_field(OSThread, _pthread_id, pthread_t) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ /* Posix Thread IDs */ \ /**********************/ \ \ declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(pthread_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_LINUX_X86_VM_VMSTRUCTS_LINUX_X86_HPP diff --git a/hotspot/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp b/hotspot/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp index 46c7912c372..34b82a96d79 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp +++ b/hotspot/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp @@ -30,21 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_LINUX_ZERO_VM_VMSTRUCTS_LINUX_ZERO_HPP diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp index 58113a9ea49..40d6ae735aa 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp @@ -29,44 +29,32 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ \ nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - /* This must be the last entry, and must be present */ \ - last_entry() + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ /* Solaris Thread IDs */ \ /**********************/ \ \ - declare_unsigned_integer_type(OSThread::thread_id_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(OSThread::thread_id_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ \ /************************/ \ /* JavaThread constants */ \ /************************/ \ \ - declare_constant(JavaFrameAnchor::flushed) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_constant(JavaFrameAnchor::flushed) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_SOLARIS_SPARC_VM_VMSTRUCTS_SOLARIS_SPARC_HPP diff --git a/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp index a2a4f7c60b7..523fdc7cc42 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp @@ -29,36 +29,24 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ /* Solaris Thread IDs */ \ /**********************/ \ \ - declare_unsigned_integer_type(OSThread::thread_id_t) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(OSThread::thread_id_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_SOLARIS_X86_VM_VMSTRUCTS_SOLARIS_X86_HPP diff --git a/hotspot/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp index 69d25c93186..a392b63632c 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp @@ -29,32 +29,21 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ \ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() + unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \ +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ - declare_unsigned_integer_type(OSThread::thread_id_t) \ - /* This must be the last entry, and must be present */ \ - last_entry() + declare_unsigned_integer_type(OSThread::thread_id_t) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ - \ - /* This must be the last entry, and must be present */ \ - last_entry() +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) #endif // OS_CPU_WINDOWS_X86_VM_VMSTRUCTS_WINDOWS_X86_HPP diff --git a/hotspot/src/share/tools/launcher/java.c b/hotspot/src/share/tools/launcher/java.c index 5ebfb9a8dc3..63f11d77c86 100644 --- a/hotspot/src/share/tools/launcher/java.c +++ b/hotspot/src/share/tools/launcher/java.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -808,7 +808,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { static int parse_stack_size(const char *s, jlong *result) { jlong n = 0; - int args_read = sscanf(s, jlong_format_specifier(), &n); + int args_read = sscanf(s, JLONG_FORMAT, &n); if (args_read != 1) { return 0; } diff --git a/hotspot/src/share/tools/launcher/java.h b/hotspot/src/share/tools/launcher/java.h index 97fba2184f7..1dd79618c84 100644 --- a/hotspot/src/share/tools/launcher/java.h +++ b/hotspot/src/share/tools/launcher/java.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -86,7 +86,6 @@ void ReportExceptionDescription(JNIEnv * env); jboolean RemovableMachineDependentOption(char * option); void PrintMachineDependentOptions(); -const char *jlong_format_specifier(); /* * Block current thread and continue execution in new thread */ diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index f7f48b4a2dc..b9170ec379e 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -862,8 +862,10 @@ uint InstructForm::oper_input_base(FormDict &globals) { ( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 || strcmp(_matrule->_rChild->_opType,"StrComp" )==0 || strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || - strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) { + strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 || + strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) { // String.(compareTo/equals/indexOf) and Arrays.equals + // and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray // take 1 control and 1 memory edges. return 2; } diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 85c3aa1c9a9..cbaf83b8fea 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3223,7 +3223,12 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co } if (try_inline_full(callee, holder_known, bc, receiver)) return true; - print_inlining(callee, _inline_bailout_msg, /*success*/ false); + + // Entire compilation could fail during try_inline_full call. + // In that case printing inlining decision info is useless. + if (!bailed_out()) + print_inlining(callee, _inline_bailout_msg, /*success*/ false); + return false; } @@ -3753,7 +3758,8 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode push_scope(callee, cont); // the BlockListBuilder for the callee could have bailed out - CHECK_BAILOUT_(false); + if (bailed_out()) + return false; // Temporarily set up bytecode stream so we can append instructions // (only using the bci of this stream) @@ -3819,7 +3825,8 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode iterate_all_blocks(callee_start_block == NULL); // If we bailed out during parsing, return immediately (this is bad news) - if (bailed_out()) return false; + if (bailed_out()) + return false; // iterate_all_blocks theoretically traverses in random order; in // practice, we have only traversed the continuation if we are @@ -3828,9 +3835,6 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode !continuation()->is_set(BlockBegin::was_visited_flag), "continuation should not have been parsed yet if we created it"); - // If we bailed out during parsing, return immediately (this is bad news) - CHECK_BAILOUT_(false); - // At this point we are almost ready to return and resume parsing of // the caller back in the GraphBuilder. The only thing we want to do // first is an optimization: during parsing of the callee we @@ -4171,7 +4175,10 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes else log->inline_success("receiver is statically known"); } else { - log->inline_fail(msg); + if (msg != NULL) + log->inline_fail(msg); + else + log->inline_fail("reason unknown"); } } diff --git a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp index a2f6f86fd85..68e0feb5b83 100644 --- a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp +++ b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -360,7 +360,7 @@ void InstructionPrinter::do_Constant(Constant* x) { ValueType* t = x->type(); switch (t->tag()) { case intTag : output()->print("%d" , t->as_IntConstant ()->value()); break; - case longTag : output()->print(os::jlong_format_specifier(), t->as_LongConstant()->value()); output()->print("L"); break; + case longTag : output()->print(JLONG_FORMAT, t->as_LongConstant()->value()); output()->print("L"); break; case floatTag : output()->print("%g" , t->as_FloatConstant ()->value()); break; case doubleTag : output()->print("%gD" , t->as_DoubleConstant()->value()); break; case objectTag : print_object(x); break; diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 178d1867179..7a0563c6a20 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, 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 @@ -1563,7 +1563,7 @@ void LIR_Const::print_value_on(outputStream* out) const { switch (type()) { case T_ADDRESS:out->print("address:%d",as_jint()); break; case T_INT: out->print("int:%d", as_jint()); break; - case T_LONG: out->print("lng:%lld", as_jlong()); break; + case T_LONG: out->print("lng:" JLONG_FORMAT, as_jlong()); break; case T_FLOAT: out->print("flt:%f", as_jfloat()); break; case T_DOUBLE: out->print("dbl:%f", as_jdouble()); break; case T_OBJECT: out->print("obj:0x%x", as_jobject()); break; diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index e81636c524a..16451f6d526 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -147,7 +147,7 @@ "Inline methods containing exception handlers " \ "(NOTE: does not work with current backend)") \ \ - develop(bool, InlineSynchronizedMethods, true, \ + product(bool, InlineSynchronizedMethods, true, \ "Inline synchronized methods") \ \ develop(bool, InlineNIOCheckIndex, true, \ diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index f2e77241960..9b532b8e26b 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -1,4 +1,4 @@ -/* 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 @@ -645,7 +645,7 @@ class CompileReplay : public StackObj { java_mirror->bool_field_put(fd.offset(), value); } else if (strcmp(field_signature, "J") == 0) { jlong value; - if (sscanf(string_value, INT64_FORMAT, &value) != 1) { + if (sscanf(string_value, JLONG_FORMAT, &value) != 1) { fprintf(stderr, "Error parsing long: %s\n", string_value); return; } diff --git a/hotspot/src/share/vm/ci/ciType.cpp b/hotspot/src/share/vm/ci/ciType.cpp index 47412130f04..e74dd921804 100644 --- a/hotspot/src/share/vm/ci/ciType.cpp +++ b/hotspot/src/share/vm/ci/ciType.cpp @@ -59,6 +59,19 @@ bool ciType::is_subtype_of(ciType* type) { return false; } +// ------------------------------------------------------------------ +// ciType::name +// +// Return the name of this type +const char* ciType::name() { + if (is_primitive_type()) { + return type2name(basic_type()); + } else { + assert(is_klass(), "must be"); + return as_klass()->name()->as_utf8(); + } +} + // ------------------------------------------------------------------ // ciType::print_impl // @@ -73,7 +86,8 @@ void ciType::print_impl(outputStream* st) { // // Print the name of this type void ciType::print_name_on(outputStream* st) { - st->print(type2name(basic_type())); + ResourceMark rm; + st->print(name()); } diff --git a/hotspot/src/share/vm/ci/ciType.hpp b/hotspot/src/share/vm/ci/ciType.hpp index 807ae1bec92..25f79e01263 100644 --- a/hotspot/src/share/vm/ci/ciType.hpp +++ b/hotspot/src/share/vm/ci/ciType.hpp @@ -77,6 +77,7 @@ public: bool is_type() const { return true; } bool is_classless() const { return is_primitive_type(); } + const char* name(); virtual void print_name_on(outputStream* st); void print_name() { print_name_on(tty); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 9dd0640de06..557707ba432 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -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 @@ -59,6 +59,7 @@ #include "services/classLoadingService.hpp" #include "services/threadService.hpp" #include "utilities/array.hpp" +#include "utilities/globalDefinitions.hpp" // We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A @@ -970,6 +971,12 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); + parse_annotations(loader_data, + runtime_visible_annotations, + runtime_visible_annotations_length, + cp, + parsed_annotations, + CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { runtime_invisible_annotations_length = attribute_length; @@ -1216,19 +1223,16 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, field->initialize(access_flags.as_short(), name_index, signature_index, - constantvalue_index, - 0); - if (parsed_annotations.has_any_annotations()) - parsed_annotations.apply_to(field); - + constantvalue_index); BasicType type = cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); + field->set_allocation_type(atype); - // The correct offset is computed later (all oop fields will be located together) - // We temporarily store the allocation type in the offset field - field->set_offset(atype); + // After field is initialized with type, we can augment it with aux info + if (parsed_annotations.has_any_annotations()) + parsed_annotations.apply_to(field); } int index = length; @@ -1259,17 +1263,13 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, field->initialize(JVM_ACC_FIELD_INTERNAL, injected[n].name_index, injected[n].signature_index, - 0, 0); BasicType type = FieldType::basic_type(injected[n].signature()); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(false, type); - - // The correct offset is computed later (all oop fields will be located together) - // We temporarily store the allocation type in the offset field - field->set_offset(atype); + field->set_allocation_type(atype); index++; } } @@ -1735,7 +1735,8 @@ int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) { } // Sift through annotations, looking for those significant to the VM: -void ClassFileParser::parse_annotations(u1* buffer, int limit, +void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, + u1* buffer, int limit, constantPoolHandle cp, ClassFileParser::AnnotationCollector* coll, TRAPS) { @@ -1752,9 +1753,12 @@ void ClassFileParser::parse_annotations(u1* buffer, int limit, e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;' e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME' e_size = 11, // end of 'e' annotation - c_tag_val = 'c', - c_con_off = 7, // utf8 payload, such as 'I' or 'Ljava/lang/String;' + c_tag_val = 'c', // payload is type + c_con_off = 7, // utf8 payload, such as 'I' c_size = 9, // end of 'c' annotation + s_tag_val = 's', // payload is String + s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;' + s_size = 9, min_size = 6 // smallest possible size (zero members) }; while ((--nann) >= 0 && (index-2 + min_size <= limit)) { @@ -1773,57 +1777,63 @@ void ClassFileParser::parse_annotations(u1* buffer, int limit, } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(aname); + AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); - // If there are no values, just set the bit and move on: - if (count == 0) continue; - // For the record, here is how annotation payloads can be collected. - // Suppose we want to capture @Retention.value. Here is how: - //if (id == AnnotationCollector::_class_Retention) { - // Symbol* payload = NULL; - // if (count == 1 - // && e_size == (index0 - index) // match size - // && e_tag_val == *(abase + tag_off) - // && (check_symbol_at(cp, Bytes::get_Java_u2(abase + e_type_off)) - // == vmSymbols::RetentionPolicy_signature()) - // && member == vmSymbols::value_name()) { - // payload = check_symbol_at(cp, Bytes::get_Java_u2(abase + e_con_off)); - // } - // check_property(payload != NULL, - // "Invalid @Retention annotation at offset %u in class file %s", - // index0, CHECK); - // if (payload != NULL) { - // payload->increment_refcount(); - // coll->_class_RetentionPolicy = payload; - // } - //} + if (id == AnnotationCollector::_sun_misc_Contended) { + if (count == 1 + && s_size == (index - index0) // match size + && s_tag_val == *(abase + tag_off) + && member == vmSymbols::value_name()) { + u2 group_index = Bytes::get_Java_u2(abase + s_con_off); + coll->set_contended_group(group_index); + } else { + coll->set_contended_group(0); // default contended group + } + coll->set_contended(true); + } else { + coll->set_contended(false); + } } } -ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) { +ClassFileParser::AnnotationCollector::ID +ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data, + Symbol* name) { vmSymbols::SID sid = vmSymbols::find_sid(name); + // Privileged code can use all annotations. Other code silently drops some. + bool privileged = loader_data->is_the_null_class_loader_data() || + loader_data->is_anonymous(); switch (sid) { case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code return _method_ForceInline; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code return _method_DontInline; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code return _method_LambdaForm_Compiled; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature): if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code return _method_LambdaForm_Hidden; + case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature): + if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes + if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges + return _sun_misc_Contended; default: break; } return AnnotationCollector::_unknown; } void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { - fatal("no field annotations yet"); + if (is_contended()) + f->set_contended_group(contended_group()); } void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { @@ -1838,7 +1848,7 @@ void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { } void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) { - fatal("no class annotations yet"); + k->set_is_contended(is_contended()); } @@ -2148,9 +2158,21 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, cp, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { method_parameters_length = cfs->get_u1_fast(); + // Track the actual size (note: this is written for clarity; a + // decent compiler will CSE and constant-fold this into a single + // expression) + u2 actual_size = 1; method_parameters_data = cfs->get_u1_buffer(); + actual_size += 2 * method_parameters_length; cfs->skip_u2_fast(method_parameters_length); + actual_size += 4 * method_parameters_length; cfs->skip_u4_fast(method_parameters_length); + // Enforce attribute length + if (method_attribute_length != actual_size) { + classfile_parse_error( + "Invalid MethodParameters method attribute length %u in class file %s", + method_attribute_length, CHECK_(nullHandle)); + } // ignore this attribute if it cannot be reflected if (!SystemDictionary::Parameter_klass_loaded()) method_parameters_length = 0; @@ -2181,7 +2203,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(runtime_visible_annotations, + parse_annotations(loader_data, + runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); @@ -2297,7 +2320,10 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data); method_parameters_data += 2; - elem[i].flags = Bytes::get_Java_u4(method_parameters_data); + u4 flags = Bytes::get_Java_u4(method_parameters_data); + // This caused an alignment fault on Sparc, if flags was a u4 + elem[i].flags_lo = extract_low_short_from_int(flags); + elem[i].flags_hi = extract_high_short_from_int(flags); method_parameters_data += 4; } } @@ -2475,26 +2501,38 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, *has_default_methods = true; } methods->at_put(index, method()); - if (*methods_annotations == NULL) { - *methods_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + + if (method_annotations != NULL) { + if (*methods_annotations == NULL) { + *methods_annotations = + MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + } + (*methods_annotations)->at_put(index, method_annotations); } - (*methods_annotations)->at_put(index, method_annotations); - if (*methods_parameter_annotations == NULL) { - *methods_parameter_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + + if (method_parameter_annotations != NULL) { + if (*methods_parameter_annotations == NULL) { + *methods_parameter_annotations = + MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + } + (*methods_parameter_annotations)->at_put(index, method_parameter_annotations); } - (*methods_parameter_annotations)->at_put(index, method_parameter_annotations); - if (*methods_default_annotations == NULL) { - *methods_default_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + + if (method_default_annotations != NULL) { + if (*methods_default_annotations == NULL) { + *methods_default_annotations = + MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + } + (*methods_default_annotations)->at_put(index, method_default_annotations); } - (*methods_default_annotations)->at_put(index, method_default_annotations); - if (*methods_type_annotations == NULL) { - *methods_type_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + + if (method_type_annotations != NULL) { + if (*methods_type_annotations == NULL) { + *methods_type_annotations = + MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + } + (*methods_type_annotations)->at_put(index, method_type_annotations); } - (*methods_type_annotations)->at_put(index, method_type_annotations); } if (_need_verify && length > 1) { @@ -2886,7 +2924,8 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(runtime_visible_annotations, + parse_annotations(loader_data, + runtime_visible_annotations, runtime_visible_annotations_length, cp, parsed_annotations, @@ -3309,8 +3348,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - // These need to be oop pointers because they are allocated lazily - // inside parse_methods inside a nested HandleMark + Array* methods_annotations = NULL; Array* methods_parameter_annotations = NULL; Array* methods_default_annotations = NULL; @@ -3405,18 +3443,21 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Size of Java itable (in words) itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); + // get the padding width from the option + // TODO: Ask VM about specific CPU we are running on + int pad_size = ContendedPaddingWidth; + // Field size and offset computation int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size(); #ifndef PRODUCT int orig_nonstatic_field_size = 0; #endif - int static_field_size = 0; int next_static_oop_offset; int next_static_double_offset; int next_static_word_offset; int next_static_short_offset; int next_static_byte_offset; - int next_static_type_offset; + int next_static_padded_offset; int next_nonstatic_oop_offset; int next_nonstatic_double_offset; int next_nonstatic_word_offset; @@ -3426,11 +3467,36 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, int first_nonstatic_oop_offset; int first_nonstatic_field_offset; int next_nonstatic_field_offset; + int next_nonstatic_padded_offset; + + // Count the contended fields by type. + int static_contended_count = 0; + int nonstatic_contended_count = 0; + FieldAllocationCount fac_contended; + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + if (fs.is_contended()) { + fac_contended.count[atype]++; + if (fs.access_flags().is_static()) { + static_contended_count++; + } else { + nonstatic_contended_count++; + } + } + } + int contended_count = static_contended_count + nonstatic_contended_count; + // Calculate the starting byte offsets next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); + + // class is contended, pad before all the fields + if (parsed_annotations.is_contended()) { + next_static_oop_offset += pad_size; + } + next_static_double_offset = next_static_oop_offset + - (fac.count[STATIC_OOP] * heapOopSize); + ((fac.count[STATIC_OOP] - fac_contended.count[STATIC_OOP]) * heapOopSize); if ( fac.count[STATIC_DOUBLE] && (Universe::field_type_should_be_aligned(T_DOUBLE) || Universe::field_type_should_be_aligned(T_LONG)) ) { @@ -3438,25 +3504,29 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } next_static_word_offset = next_static_double_offset + - (fac.count[STATIC_DOUBLE] * BytesPerLong); + ((fac.count[STATIC_DOUBLE] - fac_contended.count[STATIC_DOUBLE]) * BytesPerLong); next_static_short_offset = next_static_word_offset + - (fac.count[STATIC_WORD] * BytesPerInt); + ((fac.count[STATIC_WORD] - fac_contended.count[STATIC_WORD]) * BytesPerInt); next_static_byte_offset = next_static_short_offset + - (fac.count[STATIC_SHORT] * BytesPerShort); - next_static_type_offset = align_size_up((next_static_byte_offset + - fac.count[STATIC_BYTE] ), wordSize ); - static_field_size = (next_static_type_offset - - next_static_oop_offset) / wordSize; + ((fac.count[STATIC_SHORT] - fac_contended.count[STATIC_SHORT]) * BytesPerShort); + next_static_padded_offset = next_static_byte_offset + + ((fac.count[STATIC_BYTE] - fac_contended.count[STATIC_BYTE]) * 1); first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size * heapOopSize; + + // class is contended, pad before all the fields + if (parsed_annotations.is_contended()) { + first_nonstatic_field_offset += pad_size; + } + next_nonstatic_field_offset = first_nonstatic_field_offset; - unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE]; - unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD]; - unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT]; - unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE]; - unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP]; + unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; + unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; + unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; + unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; + unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; bool super_has_nonstatic_fields = (super_klass() != NULL && super_klass->has_nonstatic_fields()); @@ -3529,12 +3599,12 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } if( allocation_style == 0 ) { - // Fields order: oops, longs/doubles, ints, shorts/chars, bytes + // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields next_nonstatic_oop_offset = next_nonstatic_field_offset; next_nonstatic_double_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } else if( allocation_style == 1 ) { - // Fields order: longs/doubles, ints, shorts/chars, bytes, oops + // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields next_nonstatic_double_offset = next_nonstatic_field_offset; } else if( allocation_style == 2 ) { // Fields allocation: oops fields in super and sub classes are together. @@ -3613,27 +3683,33 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, (nonstatic_word_count * BytesPerInt); next_nonstatic_byte_offset = next_nonstatic_short_offset + (nonstatic_short_count * BytesPerShort); + next_nonstatic_padded_offset = next_nonstatic_byte_offset + + nonstatic_byte_count; - int notaligned_offset; - if( allocation_style == 0 ) { - notaligned_offset = next_nonstatic_byte_offset + nonstatic_byte_count; - } else { // allocation_style == 1 - next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count; + // let oops jump before padding with this allocation style + if( allocation_style == 1 ) { + next_nonstatic_oop_offset = next_nonstatic_padded_offset; if( nonstatic_oop_count > 0 ) { next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); } - notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); + next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } - next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); - nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/heapOopSize); // Iterate over fields again and compute correct offsets. // The field allocation type was temporarily stored in the offset slot. // oop fields are located before non-oop fields (static and non-static). for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // contended fields are handled below + if (fs.is_contended()) continue; + int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.offset(); + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + // pack the rest of the fields switch (atype) { case STATIC_OOP: real_offset = next_static_oop_offset; @@ -3722,13 +3798,225 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, fs.set_offset(real_offset); } + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contended_count > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + if (nonstatic_contended_count > 0) { + next_nonstatic_padded_offset += pad_size; + } + + // collect all contended groups + BitMap bm(cp->size()); + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + // skip already laid out fields + if (fs.is_offset_set()) continue; + + if (fs.is_contended()) { + bm.set_bit(fs.contended_group()); + } + } + + int current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // handle statics below + if (fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + case NONSTATIC_BYTE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += 1; + break; + + case NONSTATIC_SHORT: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerShort; + break; + + case NONSTATIC_WORD: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerInt; + break; + + case NONSTATIC_DOUBLE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerLong; + break; + + case NONSTATIC_OOP: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += heapOopSize; + + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + break; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_nonstatic_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_nonstatic_padded_offset += pad_size; + } + } + + // handle static fields + + // if there is at least one contended field, we need to have pre-padding for them + if (static_contended_count > 0) { + next_static_padded_offset += pad_size; + } + + current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // non-statics already handled above + if (!fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + + case STATIC_BYTE: + next_static_padded_offset = align_size_up(next_static_padded_offset, 1); + real_offset = next_static_padded_offset; + next_static_padded_offset += 1; + break; + + case STATIC_SHORT: + next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerShort); + real_offset = next_static_padded_offset; + next_static_padded_offset += BytesPerShort; + break; + + case STATIC_WORD: + next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerInt); + real_offset = next_static_padded_offset; + next_static_padded_offset += BytesPerInt; + break; + + case STATIC_DOUBLE: + next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerLong); + real_offset = next_static_padded_offset; + next_static_padded_offset += BytesPerLong; + break; + + case STATIC_OOP: + next_static_padded_offset = align_size_up(next_static_padded_offset, heapOopSize); + real_offset = next_static_padded_offset; + next_static_padded_offset += heapOopSize; + break; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_static_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_static_padded_offset += pad_size; + } + + } + + } // handle contended + // Size of instances int instance_size; + int notaligned_offset = next_nonstatic_padded_offset; + + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (parsed_annotations.is_contended()) { + notaligned_offset += pad_size; + next_static_padded_offset += pad_size; + } + + int next_static_type_offset = align_size_up(next_static_padded_offset, wordSize); + int static_field_size = (next_static_type_offset - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + + next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); + nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset + - first_nonstatic_field_offset)/heapOopSize); + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); instance_size = align_object_size(next_nonstatic_type_offset / wordSize); - assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value"); + assert(instance_size == align_object_size(align_size_up( + (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations.is_contended()) ? pad_size : 0)), + wordSize) / wordSize), "consistent layout helper value"); // Number of non-static oop map blocks allocated at end of klass. const unsigned int total_oop_map_count = @@ -3912,7 +4200,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // check that if this class is an interface then it doesn't have static methods if (this_klass->is_interface()) { - check_illegal_static_method(this_klass, CHECK_(nullHandle)); + /* An interface in a JAVA 8 classfile can be static */ + if (_major_version < JAVA_8_VERSION) { + check_illegal_static_method(this_klass, CHECK_(nullHandle)); + } } @@ -4005,6 +4296,18 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } #endif +#ifndef PRODUCT + if (PrintFieldLayout) { + print_field_layout(name, + fields, + cp, + instance_size, + first_nonstatic_field_offset, + next_nonstatic_field_offset, + next_static_type_offset); + } +#endif + // preserve result across HandleMark preserve_this_klass = this_klass(); } @@ -4017,6 +4320,38 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, return this_klass; } +void ClassFileParser::print_field_layout(Symbol* name, + Array* fields, + constantPoolHandle cp, + int instance_size, + int instance_fields_start, + int instance_fields_end, + int static_fields_end) { + tty->print("%s: field layout\n", name->as_klass_external_name()); + tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---"); + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + if (!fs.access_flags().is_static()) { + tty->print(" @%3d \"%s\" %s\n", + fs.offset(), + fs.name()->as_klass_external_name(), + fs.signature()->as_klass_external_name()); + } + } + tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---"); + tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---"); + tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---"); + for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + tty->print(" @%3d \"%s\" %s\n", + fs.offset(), + fs.name()->as_klass_external_name(), + fs.signature()->as_klass_external_name()); + } + } + tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---"); + tty->print("\n"); +} + unsigned int ClassFileParser::compute_oop_map_count(instanceKlassHandle super, unsigned int nonstatic_oop_map_count, @@ -4466,6 +4801,7 @@ void ClassFileParser::verify_legal_method_modifiers( const bool is_bridge = (flags & JVM_ACC_BRIDGE) != 0; const bool is_strict = (flags & JVM_ACC_STRICT) != 0; const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0; + const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; const bool major_gte_8 = _major_version >= JAVA_8_VERSION; const bool is_initializer = (name == vmSymbols::object_initializer_name()); @@ -4473,11 +4809,33 @@ void ClassFileParser::verify_legal_method_modifiers( bool is_illegal = false; if (is_interface) { - if (!is_public || is_static || is_final || is_native || - ((is_synchronized || is_strict) && major_gte_15 && - (!major_gte_8 || is_abstract)) || - (!major_gte_8 && !is_abstract)) { - is_illegal = true; + if (major_gte_8) { + // Class file version is JAVA_8_VERSION or later Methods of + // interfaces may set any of the flags except ACC_PROTECTED, + // ACC_FINAL, ACC_NATIVE, and ACC_SYNCHRONIZED; they must + // have exactly one of the ACC_PUBLIC or ACC_PRIVATE flags set. + if ((is_public == is_private) || /* Only one of private and public should be true - XNOR */ + (is_native || is_protected || is_final || is_synchronized) || + // If a specific method of a class or interface has its + // ACC_ABSTRACT flag set, it must not have any of its + // ACC_FINAL, ACC_NATIVE, ACC_PRIVATE, ACC_STATIC, + // ACC_STRICT, or ACC_SYNCHRONIZED flags set. No need to + // check for ACC_FINAL, ACC_NATIVE or ACC_SYNCHRONIZED as + // those flags are illegal irrespective of ACC_ABSTRACT being set or not. + (is_abstract && (is_private || is_static || is_strict))) { + is_illegal = true; + } + } else if (major_gte_15) { + // Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION) + if (!is_public || is_static || is_final || is_synchronized || + is_native || !is_abstract || is_strict) { + is_illegal = true; + } + } else { + // Class file version is pre-JAVA_1_5_VERSION + if (!is_public || is_static || is_final || is_native || !is_abstract) { + is_illegal = true; + } } } else { // not interface if (is_initializer) { diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index 5a5d3fc397a..cc0193a15f5 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -95,17 +95,20 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { _method_DontInline, _method_LambdaForm_Compiled, _method_LambdaForm_Hidden, + _sun_misc_Contended, _annotation_LIMIT }; const Location _location; int _annotations_present; + u2 _contended_group; + AnnotationCollector(Location location) : _location(location), _annotations_present(0) { assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, ""); } // If this annotation name has an ID, report it (or _none). - ID annotation_index(Symbol* name); + ID annotation_index(ClassLoaderData* loader_data, Symbol* name); // Set the annotation name: void set_annotation(ID id) { assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob"); @@ -114,6 +117,12 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // Report if the annotation is present. bool has_any_annotations() { return _annotations_present != 0; } bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; } + + void set_contended_group(u2 group) { _contended_group = group; } + u2 contended_group() { return _contended_group; } + + void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } + bool is_contended() { return has_annotation(_sun_misc_Contended); } }; class FieldAnnotationCollector: public AnnotationCollector { public: @@ -177,6 +186,14 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS); + void print_field_layout(Symbol* name, + Array* fields, + constantPoolHandle cp, + int instance_size, + int instance_fields_start, + int instance_fields_end, + int static_fields_end); + // Method parsing methodHandle parse_method(ClassLoaderData* loader_data, constantPoolHandle cp, @@ -247,7 +264,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int runtime_invisible_annotations_length, TRAPS); int skip_annotation(u1* buffer, int limit, int index); int skip_annotation_value(u1* buffer, int limit, int index); - void parse_annotations(u1* buffer, int limit, constantPoolHandle cp, + void parse_annotations(ClassLoaderData* loader_data, + u1* buffer, int limit, constantPoolHandle cp, /* Results (currently, only one result is supported): */ AnnotationCollector* result, TRAPS); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 40c397de887..22cc8cf9bb1 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -318,6 +318,7 @@ ClassLoaderData::~ClassLoaderData() { } Metaspace* ClassLoaderData::metaspace_non_null() { + assert(!DumpSharedSpaces, "wrong metaspace!"); // If the metaspace has not been allocated, create a new one. Might want // to create smaller arena for Reflection class loaders also. // The reason for the delayed allocation is because some class loaders are diff --git a/hotspot/src/share/vm/classfile/defaultMethods.cpp b/hotspot/src/share/vm/classfile/defaultMethods.cpp index ac593a7ef24..ce516b84bc1 100644 --- a/hotspot/src/share/vm/classfile/defaultMethods.cpp +++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp @@ -1285,13 +1285,15 @@ static void merge_in_new_methods(InstanceKlass* klass, enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS }; - Array* original_annots[NUM_ARRAYS]; + Array* original_annots[NUM_ARRAYS] = { NULL }; Array* original_methods = klass->methods(); Annotations* annots = klass->annotations(); - original_annots[ANNOTATIONS] = annots->methods_annotations(); - original_annots[PARAMETERS] = annots->methods_parameter_annotations(); - original_annots[DEFAULTS] = annots->methods_default_annotations(); + if (annots != NULL) { + original_annots[ANNOTATIONS] = annots->methods_annotations(); + original_annots[PARAMETERS] = annots->methods_parameter_annotations(); + original_annots[DEFAULTS] = annots->methods_default_annotations(); + } Array* original_ordering = klass->method_ordering(); Array* merged_ordering = Universe::the_empty_int_array(); @@ -1370,9 +1372,15 @@ static void merge_in_new_methods(InstanceKlass* klass, // Replace klass methods with new merged lists klass->set_methods(merged_methods); - annots->set_methods_annotations(merged_annots[ANNOTATIONS]); - annots->set_methods_parameter_annotations(merged_annots[PARAMETERS]); - annots->set_methods_default_annotations(merged_annots[DEFAULTS]); + if (annots != NULL) { + annots->set_methods_annotations(merged_annots[ANNOTATIONS]); + annots->set_methods_parameter_annotations(merged_annots[PARAMETERS]); + annots->set_methods_default_annotations(merged_annots[DEFAULTS]); + } else { + assert(merged_annots[ANNOTATIONS] == NULL, "Must be"); + assert(merged_annots[PARAMETERS] == NULL, "Must be"); + assert(merged_annots[DEFAULTS] == NULL, "Must be"); + } ClassLoaderData* cld = klass->class_loader_data(); MetadataFactory::free_array(cld, original_methods); diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index cb30a83d455..fe03d3fb132 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -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 @@ -687,19 +687,6 @@ void java_lang_Class::set_array_klass(oop java_class, Klass* klass) { } -Method* java_lang_Class::resolved_constructor(oop java_class) { - Metadata* constructor = java_class->metadata_field(_resolved_constructor_offset); - assert(constructor == NULL || constructor->is_method(), "should be method"); - return ((Method*)constructor); -} - - -void java_lang_Class::set_resolved_constructor(oop java_class, Method* constructor) { - assert(constructor->is_method(), "should be method"); - java_class->metadata_field_put(_resolved_constructor_offset, constructor); -} - - bool java_lang_Class::is_primitive(oop java_class) { // should assert: //assert(java_lang_Class::is_instance(java_class), "must be a Class object"); @@ -924,7 +911,6 @@ jlong java_lang_Thread::stackSize(oop java_thread) { // Write the thread status value to threadStatus field in java.lang.Thread java class. void java_lang_Thread::set_thread_status(oop java_thread, java_lang_Thread::ThreadStatus status) { - assert(JavaThread::current()->thread_state() == _thread_in_vm, "Java Thread is not running in vm"); // The threadStatus is only present starting in 1.5 if (_thread_status_offset > 0) { java_thread->int_field_put(_thread_status_offset, status); @@ -1158,179 +1144,43 @@ void java_lang_Throwable::print(Handle throwable, outputStream* st) { } } -// Print stack trace element to resource allocated buffer -char* java_lang_Throwable::print_stack_element_to_buffer(Method* method, int bci) { - // Get strings and string lengths - InstanceKlass* klass = method->method_holder(); - const char* klass_name = klass->external_name(); - int buf_len = (int)strlen(klass_name); - char* source_file_name; - if (klass->source_file_name() == NULL) { - source_file_name = NULL; - } else { - source_file_name = klass->source_file_name()->as_C_string(); - buf_len += (int)strlen(source_file_name); - } - char* method_name = method->name()->as_C_string(); - buf_len += (int)strlen(method_name); +// After this many redefines, the stack trace is unreliable. +const int MAX_VERSION = USHRT_MAX; - // Allocate temporary buffer with extra space for formatting and line number - char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); +// Helper backtrace functions to store bci|version together. +static inline int merge_bci_and_version(int bci, int version) { + // only store u2 for version, checking for overflow. + if (version > USHRT_MAX || version < 0) version = MAX_VERSION; + assert((jushort)bci == bci, "bci should be short"); + return build_int_from_shorts(version, bci); +} - // Print stack trace line in buffer - sprintf(buf, "\tat %s.%s", klass_name, method_name); +static inline int bci_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} +static inline int version_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + +static inline bool version_matches(Method* method, int version) { + return (method->constants()->version() == version && version < MAX_VERSION); +} + +static inline int get_line_number(Method* method, int bci) { + int line_number = 0; if (method->is_native()) { - strcat(buf, "(Native Method)"); + // Negative value different from -1 below, enabling Java code in + // class java.lang.StackTraceElement to distinguish "native" from + // "no LineNumberTable". JDK tests for -2. + line_number = -2; } else { - int line_number = method->line_number_from_bci(bci); - if (source_file_name != NULL && (line_number != -1)) { - // Sourcename and linenumber - sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); - } else if (source_file_name != NULL) { - // Just sourcename - sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); - } else { - // Neither soucename and linenumber - sprintf(buf + (int)strlen(buf), "(Unknown Source)"); - } - nmethod* nm = method->code(); - if (WizardMode && nm != NULL) { - sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); + // Returns -1 if no LineNumberTable, and otherwise actual line number + line_number = method->line_number_from_bci(bci); + if (line_number == -1 && ShowHiddenFrames) { + line_number = bci + 1000000; } } - - return buf; -} - - -void java_lang_Throwable::print_stack_element(Handle stream, Method* method, int bci) { - ResourceMark rm; - char* buf = print_stack_element_to_buffer(method, bci); - print_to_stream(stream, buf); -} - -void java_lang_Throwable::print_stack_element(outputStream *st, Method* method, int bci) { - ResourceMark rm; - char* buf = print_stack_element_to_buffer(method, bci); - st->print_cr("%s", buf); -} - -void java_lang_Throwable::print_to_stream(Handle stream, const char* str) { - if (stream.is_null()) { - tty->print_cr("%s", str); - } else { - EXCEPTION_MARK; - JavaValue result(T_VOID); - Handle arg (THREAD, oopFactory::new_charArray(str, THREAD)); - if (!HAS_PENDING_EXCEPTION) { - JavaCalls::call_virtual(&result, - stream, - KlassHandle(THREAD, stream->klass()), - vmSymbols::println_name(), - vmSymbols::char_array_void_signature(), - arg, - THREAD); - } - // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. - if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION; - } - -} - - -const char* java_lang_Throwable::no_stack_trace_message() { - return "\t<>"; -} - - -// Currently used only for exceptions occurring during startup -void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { - Thread *THREAD = Thread::current(); - Handle h_throwable(THREAD, throwable); - while (h_throwable.not_null()) { - objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); - if (result.is_null()) { - st->print_cr(no_stack_trace_message()); - return; - } - - while (result.not_null()) { - typeArrayHandle methods (THREAD, - typeArrayOop(result->obj_at(trace_methods_offset))); - typeArrayHandle bcis (THREAD, - typeArrayOop(result->obj_at(trace_bcis_offset))); - - if (methods.is_null() || bcis.is_null()) { - st->print_cr(no_stack_trace_message()); - return; - } - - int length = methods()->length(); - for (int index = 0; index < length; index++) { - Method* method = ((Method*)methods()->metadata_at(index)); - if (method == NULL) goto handle_cause; - int bci = bcis->ushort_at(index); - print_stack_element(st, method, bci); - } - result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); - } - handle_cause: - { - EXCEPTION_MARK; - JavaValue result(T_OBJECT); - JavaCalls::call_virtual(&result, - h_throwable, - KlassHandle(THREAD, h_throwable->klass()), - vmSymbols::getCause_name(), - vmSymbols::void_throwable_signature(), - THREAD); - // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - h_throwable = Handle(); - } else { - h_throwable = Handle(THREAD, (oop) result.get_jobject()); - if (h_throwable.not_null()) { - st->print("Caused by: "); - print(h_throwable, st); - st->cr(); - } - } - } - } -} - - -void java_lang_Throwable::print_stack_trace(oop throwable, oop print_stream) { - // Note: this is no longer used in Merlin, but we support it for compatibility. - Thread *thread = Thread::current(); - Handle stream(thread, print_stream); - objArrayHandle result (thread, objArrayOop(backtrace(throwable))); - if (result.is_null()) { - print_to_stream(stream, no_stack_trace_message()); - return; - } - - while (result.not_null()) { - typeArrayHandle methods(thread, - typeArrayOop(result->obj_at(trace_methods_offset))); - typeArrayHandle bcis (thread, - typeArrayOop(result->obj_at(trace_bcis_offset))); - - if (methods.is_null() || bcis.is_null()) { - print_to_stream(stream, no_stack_trace_message()); - return; - } - - int length = methods()->length(); - for (int index = 0; index < length; index++) { - Method* method = ((Method*)methods()->metadata_at(index)); - if (method == NULL) return; - int bci = bcis->ushort_at(index); - print_stack_element(stream, method, bci); - } - result = objArrayHandle(thread, objArrayOop(result->obj_at(trace_next_offset))); - } + return line_number; } // This class provides a simple wrapper over the internal structure of @@ -1350,13 +1200,30 @@ class BacktraceBuilder: public StackObj { enum { trace_methods_offset = java_lang_Throwable::trace_methods_offset, - trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, + trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, trace_next_offset = java_lang_Throwable::trace_next_offset, trace_size = java_lang_Throwable::trace_size, trace_chunk_size = java_lang_Throwable::trace_chunk_size }; + // get info out of chunks + static typeArrayOop get_methods(objArrayHandle chunk) { + typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); + assert(methods != NULL, "method array should be initialized in backtrace"); + return methods; + } + static typeArrayOop get_bcis(objArrayHandle chunk) { + typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); + assert(bcis != NULL, "bci array should be initialized in backtrace"); + return bcis; + } + static objArrayOop get_mirrors(objArrayHandle chunk) { + objArrayOop mirrors = objArrayOop(chunk->obj_at(trace_mirrors_offset)); + assert(mirrors != NULL, "mirror array should be initialized in backtrace"); + return mirrors; + } + // constructor for new backtrace BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { expand(CHECK); @@ -1364,6 +1231,19 @@ class BacktraceBuilder: public StackObj { _index = 0; } + BacktraceBuilder(objArrayHandle backtrace) { + _methods = get_methods(backtrace); + _bcis = get_bcis(backtrace); + _mirrors = get_mirrors(backtrace); + assert(_methods->length() == _bcis->length() && + _methods->length() == _mirrors->length(), + "method and source information arrays should match"); + + // head is the preallocated backtrace + _backtrace = _head = backtrace(); + _index = 0; + } + void expand(TRAPS) { objArrayHandle old_head(THREAD, _head); Pause_No_Safepoint_Verifier pnsv(&_nsv); @@ -1371,10 +1251,10 @@ class BacktraceBuilder: public StackObj { objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK); objArrayHandle new_head(THREAD, head); - typeArrayOop methods = oopFactory::new_metaDataArray(trace_chunk_size, CHECK); + typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK); typeArrayHandle new_methods(THREAD, methods); - typeArrayOop bcis = oopFactory::new_shortArray(trace_chunk_size, CHECK); + typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK); typeArrayHandle new_bcis(THREAD, bcis); objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); @@ -1389,7 +1269,7 @@ class BacktraceBuilder: public StackObj { _head = new_head(); _methods = new_methods(); - _bcis = new_bcis(); + _bcis = new_bcis(); _mirrors = new_mirrors(); _index = 0; } @@ -1403,7 +1283,6 @@ class BacktraceBuilder: public StackObj { // shorts. The later line number lookup would just smear the -1 // to a 0 even if it could be recorded. if (bci == SynchronizationEntryBCI) bci = 0; - assert(bci == (jushort)bci, "doesn't fit"); if (_index >= trace_chunk_size) { methodHandle mhandle(THREAD, method); @@ -1411,26 +1290,148 @@ class BacktraceBuilder: public StackObj { method = mhandle(); } - _methods->metadata_at_put(_index, method); - _bcis->ushort_at_put(_index, bci); - // we need to save the mirrors in the backtrace to keep the methods from - // being unloaded if their class loader is unloaded while we still have - // this stack trace. + _methods->short_at_put(_index, method->method_idnum()); + _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); + + // We need to save the mirrors in the backtrace to keep the class + // from being unloaded while we still have this stack trace. + assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror"); _mirrors->obj_at_put(_index, method->method_holder()->java_mirror()); _index++; } - Method* current_method() { - assert(_index >= 0 && _index < trace_chunk_size, "out of range"); - return ((Method*)_methods->metadata_at(_index)); - } - - jushort current_bci() { - assert(_index >= 0 && _index < trace_chunk_size, "out of range"); - return _bcis->ushort_at(_index); - } }; +// Print stack trace element to resource allocated buffer +char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, + int method_id, int version, int bci) { + + // Get strings and string lengths + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); + const char* klass_name = holder->external_name(); + int buf_len = (int)strlen(klass_name); + + // pushing to the stack trace added one. + Method* method = holder->method_with_idnum(method_id); + char* method_name = method->name()->as_C_string(); + buf_len += (int)strlen(method_name); + + char* source_file_name = NULL; + if (version_matches(method, version)) { + Symbol* source = holder->source_file_name(); + if (source != NULL) { + source_file_name = source->as_C_string(); + buf_len += (int)strlen(source_file_name); + } + } + + // Allocate temporary buffer with extra space for formatting and line number + char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); + + // Print stack trace line in buffer + sprintf(buf, "\tat %s.%s", klass_name, method_name); + + if (!version_matches(method, version)) { + strcat(buf, "(Redefined)"); + } else { + int line_number = get_line_number(method, bci); + if (line_number == -2) { + strcat(buf, "(Native Method)"); + } else { + if (source_file_name != NULL && (line_number != -1)) { + // Sourcename and linenumber + sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); + } else if (source_file_name != NULL) { + // Just sourcename + sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); + } else { + // Neither sourcename nor linenumber + sprintf(buf + (int)strlen(buf), "(Unknown Source)"); + } + nmethod* nm = method->code(); + if (WizardMode && nm != NULL) { + sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); + } + } + } + + return buf; +} + +void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, + int method_id, int version, int bci) { + ResourceMark rm; + char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci); + st->print_cr("%s", buf); +} + +void java_lang_Throwable::print_stack_element(outputStream *st, methodHandle method, int bci) { + Handle mirror = method->method_holder()->java_mirror(); + int method_id = method->method_idnum(); + int version = method->constants()->version(); + print_stack_element(st, mirror, method_id, version, bci); +} + +const char* java_lang_Throwable::no_stack_trace_message() { + return "\t<>"; +} + + +// Currently used only for exceptions occurring during startup +void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { + Thread *THREAD = Thread::current(); + Handle h_throwable(THREAD, throwable); + while (h_throwable.not_null()) { + objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); + if (result.is_null()) { + st->print_cr(no_stack_trace_message()); + return; + } + + while (result.not_null()) { + + // Get method id, bci, version and mirror from chunk + typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); + typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); + objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); + + int length = methods()->length(); + for (int index = 0; index < length; index++) { + Handle mirror(THREAD, mirrors->obj_at(index)); + // NULL mirror means end of stack trace + if (mirror.is_null()) goto handle_cause; + int method = methods->short_at(index); + int version = version_at(bcis->int_at(index)); + int bci = bci_at(bcis->int_at(index)); + print_stack_element(st, mirror, method, version, bci); + } + result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); + } + handle_cause: + { + EXCEPTION_MARK; + JavaValue cause(T_OBJECT); + JavaCalls::call_virtual(&cause, + h_throwable, + KlassHandle(THREAD, h_throwable->klass()), + vmSymbols::getCause_name(), + vmSymbols::void_throwable_signature(), + THREAD); + // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + h_throwable = Handle(); + } else { + h_throwable = Handle(THREAD, (oop) cause.get_jobject()); + if (h_throwable.not_null()) { + st->print("Caused by: "); + print(h_throwable, st); + st->cr(); + } + } + } + } +} void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle method, TRAPS) { if (!StackTraceInThrowable) return; @@ -1591,21 +1592,8 @@ void java_lang_Throwable::allocate_backtrace(Handle throwable, TRAPS) { // No-op if stack trace is disabled if (!StackTraceInThrowable) return; - - objArrayOop h_oop = oopFactory::new_objectArray(trace_size, CHECK); - objArrayHandle backtrace (THREAD, h_oop); - typeArrayOop m_oop = oopFactory::new_metaDataArray(trace_chunk_size, CHECK); - typeArrayHandle methods (THREAD, m_oop); - typeArrayOop b = oopFactory::new_shortArray(trace_chunk_size, CHECK); - typeArrayHandle bcis(THREAD, b); - objArrayOop mirror_oop = oopFactory::new_objectArray(trace_chunk_size, CHECK); - objArrayHandle mirrors (THREAD, mirror_oop); - - // backtrace has space for one chunk (next is NULL) - backtrace->obj_at_put(trace_methods_offset, methods()); - backtrace->obj_at_put(trace_bcis_offset, bcis()); - backtrace->obj_at_put(trace_mirrors_offset, mirrors()); - set_backtrace(throwable(), backtrace()); + BacktraceBuilder bt(CHECK); // creates a backtrace + set_backtrace(throwable(), bt.backtrace()); } @@ -1617,48 +1605,26 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t assert(throwable->is_a(SystemDictionary::Throwable_klass()), "sanity check"); - objArrayOop backtrace = (objArrayOop)java_lang_Throwable::backtrace(throwable()); - assert(backtrace != NULL, "backtrace not preallocated"); + JavaThread* THREAD = JavaThread::current(); - oop m = backtrace->obj_at(trace_methods_offset); - typeArrayOop methods = typeArrayOop(m); - assert(methods != NULL && methods->length() > 0, "method array not preallocated"); + objArrayHandle backtrace (THREAD, (objArrayOop)java_lang_Throwable::backtrace(throwable())); + assert(backtrace.not_null(), "backtrace should have been preallocated"); - oop b = backtrace->obj_at(trace_bcis_offset); - typeArrayOop bcis = typeArrayOop(b); - assert(bcis != NULL, "bci array not preallocated"); + ResourceMark rm(THREAD); + vframeStream st(THREAD); - oop mr = backtrace->obj_at(trace_mirrors_offset); - objArrayOop mirrors = objArrayOop(mr); - assert(mirrors != NULL, "bci array not preallocated"); - - assert(methods->length() == bcis->length() && - methods->length() == mirrors->length(), - "method and bci arrays should match"); - - JavaThread* thread = JavaThread::current(); - ResourceMark rm(thread); - vframeStream st(thread); + BacktraceBuilder bt(backtrace); // Unlike fill_in_stack_trace we do not skip fillInStackTrace or throwable init // methods as preallocated errors aren't created by "java" code. // fill in as much stack trace as possible + typeArrayOop methods = BacktraceBuilder::get_methods(backtrace); int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth); int chunk_count = 0; for (;!st.at_end(); st.next()) { - // Add entry and smear the -1 bci to 0 since the array only holds - // unsigned shorts. The later line number lookup would just smear - // the -1 to a 0 even if it could be recorded. - int bci = st.bci(); - if (bci == SynchronizationEntryBCI) bci = 0; - assert(bci == (jushort)bci, "doesn't fit"); - bcis->ushort_at_put(chunk_count, bci); - methods->metadata_at_put(chunk_count, st.method()); - mirrors->obj_at_put(chunk_count, - st.method()->method_holder()->java_mirror()); - + bt.push(st.method(), st.bci(), CHECK); chunk_count++; // Bail-out for deep stacks @@ -1672,7 +1638,6 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace()); assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized"); } - } @@ -1691,12 +1656,12 @@ int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) { chunk = next; } assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check"); - // Count element in remaining partial chunk - typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); - typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); - assert(methods != NULL && bcis != NULL, "sanity check"); - for (int i = 0; i < methods->length(); i++) { - if (methods->metadata_at(i) == NULL) break; + // Count element in remaining partial chunk. NULL value for mirror + // marks the end of the stack trace elements that are saved. + objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); + assert(mirrors != NULL, "sanity check"); + for (int i = 0; i < mirrors->length(); i++) { + if (mirrors->obj_at(i) == NULL) break; depth++; } } @@ -1722,25 +1687,28 @@ oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS if (chunk == NULL) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - // Get method,bci from chunk - typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); - typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); - assert(methods != NULL && bcis != NULL, "sanity check"); - methodHandle method(THREAD, ((Method*)methods->metadata_at(chunk_index))); - int bci = bcis->ushort_at(chunk_index); + // Get method id, bci, version and mirror from chunk + typeArrayOop methods = BacktraceBuilder::get_methods(chunk); + typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); + objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); + + assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); + + int method = methods->short_at(chunk_index); + int version = version_at(bcis->int_at(chunk_index)); + int bci = bci_at(bcis->int_at(chunk_index)); + Handle mirror(THREAD, mirrors->obj_at(chunk_index)); + // Chunk can be partial full - if (method.is_null()) { + if (mirror.is_null()) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - oop element = java_lang_StackTraceElement::create(method, bci, CHECK_0); + oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, CHECK_0); return element; } -oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { - // SystemDictionary::stackTraceElement_klass() will be null for pre-1.4 JDKs - assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4"); - +oop java_lang_StackTraceElement::create(Handle mirror, int method_id, int version, int bci, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -1752,37 +1720,39 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { Handle element = ik->allocate_instance_handle(CHECK_0); // Fill in class name ResourceMark rm(THREAD); - const char* str = method->method_holder()->external_name(); + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); + const char* str = holder->external_name(); oop classname = StringTable::intern((char*) str, CHECK_0); java_lang_StackTraceElement::set_declaringClass(element(), classname); + // Fill in method name + Method* method = holder->method_with_idnum(method_id); oop methodname = StringTable::intern(method->name(), CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); - // Fill in source file name - Symbol* source = method->method_holder()->source_file_name(); - if (ShowHiddenFrames && source == NULL) - source = vmSymbols::unknown_class_name(); - oop filename = StringTable::intern(source, CHECK_0); - java_lang_StackTraceElement::set_fileName(element(), filename); - // File in source line number - int line_number; - if (method->is_native()) { - // Negative value different from -1 below, enabling Java code in - // class java.lang.StackTraceElement to distinguish "native" from - // "no LineNumberTable". - line_number = -2; - } else { - // Returns -1 if no LineNumberTable, and otherwise actual line number - line_number = method->line_number_from_bci(bci); - if (line_number == -1 && ShowHiddenFrames) { - line_number = bci + 1000000; - } - } - java_lang_StackTraceElement::set_lineNumber(element(), line_number); + if (!version_matches(method, version)) { + // The method was redefined, accurate line number information isn't available + java_lang_StackTraceElement::set_fileName(element(), NULL); + java_lang_StackTraceElement::set_lineNumber(element(), -1); + } else { + // Fill in source file name and line number. + Symbol* source = holder->source_file_name(); + if (ShowHiddenFrames && source == NULL) + source = vmSymbols::unknown_class_name(); + oop filename = StringTable::intern(source, CHECK_0); + java_lang_StackTraceElement::set_fileName(element(), filename); + + int line_number = get_line_number(method, bci); + java_lang_StackTraceElement::set_lineNumber(element(), line_number); + } return element(); } +oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { + Handle mirror (THREAD, method->method_holder()->java_mirror()); + int method_id = method->method_idnum(); + return create(mirror, method_id, method->constants()->version(), bci, THREAD); +} void java_lang_reflect_AccessibleObject::compute_offsets() { Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); @@ -2949,7 +2919,6 @@ int java_lang_System::err_offset_in_bytes() { int java_lang_Class::_klass_offset; int java_lang_Class::_array_klass_offset; -int java_lang_Class::_resolved_constructor_offset; int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; GrowableArray* java_lang_Class::_fixup_mirror_list = NULL; @@ -3303,7 +3272,6 @@ void JavaClasses::check_offsets() { // Fake fields // CHECK_OFFSET("java/lang/Class", java_lang_Class, klass); // %%% this needs to be checked // CHECK_OFFSET("java/lang/Class", java_lang_Class, array_klass); // %%% this needs to be checked - // CHECK_OFFSET("java/lang/Class", java_lang_Class, resolved_constructor); // %%% this needs to be checked // java.lang.Throwable diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 5ab16251c10..478509d5c66 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -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 @@ -206,7 +206,6 @@ class java_lang_String : AllStatic { #define CLASS_INJECTED_FIELDS(macro) \ macro(java_lang_Class, klass, intptr_signature, false) \ - macro(java_lang_Class, resolved_constructor, intptr_signature, false) \ macro(java_lang_Class, array_klass, intptr_signature, false) \ macro(java_lang_Class, oop_size, int_signature, false) \ macro(java_lang_Class, static_oop_field_count, int_signature, false) @@ -218,7 +217,6 @@ class java_lang_Class : AllStatic { // The fake offsets are added by the class loader when java.lang.Class is loaded static int _klass_offset; - static int _resolved_constructor_offset; static int _array_klass_offset; static int _oop_size_offset; @@ -254,15 +252,11 @@ class java_lang_Class : AllStatic { static bool is_primitive(oop java_class); static BasicType primitive_type(oop java_class); static oop primitive_mirror(BasicType t); - // JVM_NewInstance support - static Method* resolved_constructor(oop java_class); - static void set_resolved_constructor(oop java_class, Method* constructor); // JVM_NewArray support static Klass* array_klass(oop java_class); static void set_array_klass(oop java_class, Klass* klass); // compiler support for class operations static int klass_offset_in_bytes() { return _klass_offset; } - static int resolved_constructor_offset_in_bytes() { return _resolved_constructor_offset; } static int array_klass_offset_in_bytes() { return _array_klass_offset; } // Support for classRedefinedCount field static int classRedefinedCount(oop the_class_mirror); @@ -469,8 +463,7 @@ class java_lang_Throwable: AllStatic { static int static_unassigned_stacktrace_offset; // Printing - static char* print_stack_element_to_buffer(Method* method, int bci); - static void print_to_stream(Handle stream, const char* str); + static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci); // StackTrace (programmatic access, new since 1.4) static void clear_stacktrace(oop throwable); // No stack trace available @@ -490,12 +483,9 @@ class java_lang_Throwable: AllStatic { static oop message(oop throwable); static oop message(Handle throwable); static void set_message(oop throwable, oop value); - // Print stack trace stored in exception by call-back to Java - // Note: this is no longer used in Merlin, but we still suppport - // it for compatibility. - static void print_stack_trace(oop throwable, oop print_stream); - static void print_stack_element(Handle stream, Method* method, int bci); - static void print_stack_element(outputStream *st, Method* method, int bci); + static void print_stack_element(outputStream *st, Handle mirror, int method, + int version, int bci); + static void print_stack_element(outputStream *st, methodHandle method, int bci); static void print_stack_usage(Handle stream); // Allocate space for backtrace (created but stack trace not filled in) @@ -1263,7 +1253,8 @@ class java_lang_StackTraceElement: AllStatic { static void set_lineNumber(oop element, int value); // Create an instance of StackTraceElement - static oop create(methodHandle m, int bci, TRAPS); + static oop create(Handle mirror, int method, int version, int bci, TRAPS); + static oop create(methodHandle method, int bci, TRAPS); // Debugging friend class JavaClasses; diff --git a/hotspot/src/share/vm/classfile/placeholders.cpp b/hotspot/src/share/vm/classfile/placeholders.cpp index 1babaaf978c..10d7650db58 100644 --- a/hotspot/src/share/vm/classfile/placeholders.cpp +++ b/hotspot/src/share/vm/classfile/placeholders.cpp @@ -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 @@ -142,7 +142,7 @@ PlaceholderEntry* PlaceholderTable::find_and_add(int index, unsigned int hash, } -// placeholder used to track class loading internal states +// placeholder is used to track class loading internal states // placeholder existence now for loading superclass/superinterface // superthreadQ tracks class circularity, while loading superclass/superinterface // loadInstanceThreadQ tracks load_instance_class calls @@ -153,15 +153,17 @@ PlaceholderEntry* PlaceholderTable::find_and_add(int index, unsigned int hash, // All claimants remove SeenThread after completing action // On removal: if definer and all queues empty, remove entry // Note: you can be in both placeholders and systemDictionary -// see parse_stream for redefine classes // Therefore - must always check SD first // Ignores the case where entry is not found void PlaceholderTable::find_and_remove(int index, unsigned int hash, - Symbol* name, ClassLoaderData* loader_data, Thread* thread) { + Symbol* name, ClassLoaderData* loader_data, + classloadAction action, + Thread* thread) { assert_locked_or_safepoint(SystemDictionary_lock); PlaceholderEntry *probe = get_entry(index, hash, name, loader_data); if (probe != NULL) { - // No other threads using this entry + probe->remove_seen_thread(thread, action); + // If no other threads using this entry, and this thread is not using this entry for other states if ((probe->superThreadQ() == NULL) && (probe->loadInstanceThreadQ() == NULL) && (probe->defineThreadQ() == NULL) && (probe->definer() == NULL)) { remove_entry(index, hash, name, loader_data); diff --git a/hotspot/src/share/vm/classfile/placeholders.hpp b/hotspot/src/share/vm/classfile/placeholders.hpp index af4518a462f..ca0d85af0fb 100644 --- a/hotspot/src/share/vm/classfile/placeholders.hpp +++ b/hotspot/src/share/vm/classfile/placeholders.hpp @@ -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 @@ -82,7 +82,7 @@ public: }; // find_and_add returns probe pointer - old or new - // If no entry exists, add a placeholder entry and push SeenThread + // If no entry exists, add a placeholder entry and push SeenThread for classloadAction // If entry exists, reuse entry and push SeenThread for classloadAction PlaceholderEntry* find_and_add(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data, @@ -92,9 +92,11 @@ public: void remove_entry(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data); -// Remove placeholder information + // find_and_remove first removes SeenThread for classloadAction + // If all queues are empty and definer is null, remove the PlacheholderEntry completely void find_and_remove(int index, unsigned int hash, - Symbol* name, ClassLoaderData* loader_data, Thread* thread); + Symbol* name, ClassLoaderData* loader_data, + classloadAction action, Thread* thread); // GC support. void classes_do(KlassClosure* f); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index a493e73d84d..54601625056 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -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 @@ -172,7 +172,7 @@ Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name, Handle assert(klass_h() == NULL, "Should not have result with exception pending"); Handle e(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - THROW_MSG_CAUSE_0(vmSymbols::java_lang_NoClassDefFoundError(), class_name->as_C_string(), e); + THROW_MSG_CAUSE_NULL(vmSymbols::java_lang_NoClassDefFoundError(), class_name->as_C_string(), e); } else { return NULL; } @@ -181,9 +181,9 @@ Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name, Handle if (klass_h() == NULL) { ResourceMark rm(THREAD); if (throw_error) { - THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), class_name->as_C_string()); + THROW_MSG_NULL(vmSymbols::java_lang_NoClassDefFoundError(), class_name->as_C_string()); } else { - THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string()); + THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string()); } } return (Klass*)klass_h(); @@ -343,29 +343,29 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name, } if (throw_circularity_error) { ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_ClassCircularityError(), child_name->as_C_string()); + THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), child_name->as_C_string()); } // java.lang.Object should have been found above assert(class_name != NULL, "null super class for resolving"); // Resolve the super class or interface, check results on return - Klass* superk = NULL; - superk = SystemDictionary::resolve_or_null(class_name, + Klass* superk = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, THREAD); KlassHandle superk_h(THREAD, superk); - // Note: clean up of placeholders currently in callers of - // resolve_super_or_fail - either at update_dictionary time - // or on error + // Clean up of placeholders moved so that each classloadAction registrar self-cleans up + // It is no longer necessary to keep the placeholder table alive until update_dictionary + // or error. GC used to walk the placeholder table as strong roots. + // The instanceKlass is kept alive because the class loader is on the stack, + // which keeps the loader_data alive, as well as all instanceKlasses in + // the loader_data. parseClassFile adds the instanceKlass to loader_data. { - MutexLocker mu(SystemDictionary_lock, THREAD); - PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, child_name, loader_data); - if (probe != NULL) { - probe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER); - } + MutexLocker mu(SystemDictionary_lock, THREAD); + placeholders()->find_and_remove(p_index, p_hash, child_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD); + SystemDictionary_lock->notify_all(); } if (HAS_PENDING_EXCEPTION || superk_h() == NULL) { // can null superk @@ -430,8 +430,8 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, // We're using a No_Safepoint_Verifier to catch any place where we // might potentially do a GC at all. - // SystemDictionary::do_unloading() asserts that classes are only - // unloaded at a safepoint. + // Dictionary::do_unloading() asserts that classes in SD are only + // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; dictionary()->add_protection_domain(d_index, d_hash, klass, loader_data, protection_domain, THREAD); @@ -486,7 +486,6 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) { // super class loading here. // This also is critical in cases where the original thread gets stalled // even in non-circularity situations. -// Note: only one thread can define the class, but multiple can resolve // Note: must call resolve_super_or_fail even if null super - // to force placeholder entry creation for this class for circularity detection // Caller must check for pending exception @@ -518,14 +517,6 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load( protection_domain, true, CHECK_(nh)); - // We don't redefine the class, so we just need to clean up if there - // was not an error (don't want to modify any system dictionary - // data structures). - { - MutexLocker mu(SystemDictionary_lock, THREAD); - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); - } // parallelCapable class loaders do NOT wait for parallel superclass loads to complete // Serial class loaders and bootstrap classloader do wait for superclass loads @@ -595,6 +586,10 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla // Do lookup to see if class already exist and the protection domain // has the right access + // This call uses find which checks protection domain already matches + // All subsequent calls use find_class, and set has_loaded_class so that + // before we return a result we call out to java to check for valid protection domain + // to allow returning the Klass* and add it to the pd_set if it is valid unsigned int d_hash = dictionary()->compute_hash(name, loader_data); int d_index = dictionary()->hash_to_index(d_hash); Klass* probe = dictionary()->find(d_index, d_hash, name, loader_data, @@ -652,7 +647,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } - // If the class in is in the placeholder table, class loading is in progress + // If the class is in the placeholder table, class loading is in progress if (super_load_in_progress && havesupername==true) { k = SystemDictionary::handle_parallel_super_load(name, superclassname, class_loader, protection_domain, lockObject, THREAD); @@ -664,7 +659,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } + bool throw_circularity_error = false; if (!class_has_been_loaded) { + bool load_instance_added = false; // add placeholder entry to record loading instance class // Five cases: @@ -690,7 +687,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla // No performance benefit and no deadlock issues. // case 5. parallelCapable user level classloaders - without objectLocker // Allow parallel classloading of a class/classloader pair - bool throw_circularity_error = false; + { MutexLocker mu(SystemDictionary_lock, THREAD); if (class_loader.is_null() || !is_parallelCapable(class_loader)) { @@ -726,12 +723,13 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } } - // All cases: add LOAD_INSTANCE + // All cases: add LOAD_INSTANCE holding SystemDictionary_lock // case 3: UnsyncloadClass || case 5: parallelCapable: allow competing threads to try // LOAD_INSTANCE in parallel - // add placeholder entry even if error - callers will remove on error + if (!throw_circularity_error && !class_has_been_loaded) { PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, NULL, THREAD); + load_instance_added = true; // For class loaders that do not acquire the classloader object lock, // if they did not catch another thread holding LOAD_INSTANCE, // need a check analogous to the acquire ObjectLocker/find_class @@ -740,19 +738,18 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla // class loaders holding the ObjectLock shouldn't find the class here Klass* check = find_class(d_index, d_hash, name, loader_data); if (check != NULL) { - // Klass is already loaded, so just return it + // Klass is already loaded, so return it after checking/adding protection domain k = instanceKlassHandle(THREAD, check); class_has_been_loaded = true; - newprobe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE); - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); } } } + // must throw error outside of owning lock if (throw_circularity_error) { + assert(!HAS_PENDING_EXCEPTION && load_instance_added == false,"circularity error cleanup"); ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_ClassCircularityError(), name->as_C_string()); + THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), name->as_C_string()); } if (!class_has_been_loaded) { @@ -782,20 +779,6 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } - // clean up placeholder entries for success or error - // This cleans up LOAD_INSTANCE entries - // It also cleans up LOAD_SUPER entries on errors from - // calling load_instance_class - { - MutexLocker mu(SystemDictionary_lock, THREAD); - PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, name, loader_data); - if (probe != NULL) { - probe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE); - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); - } - } - // If everything was OK (no exceptions, no null return value), and // class_loader is NOT the defining loader, do a little more bookkeeping. if (!HAS_PENDING_EXCEPTION && !k.is_null() && @@ -819,18 +802,22 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } } - if (HAS_PENDING_EXCEPTION || k.is_null()) { - // On error, clean up placeholders - { - MutexLocker mu(SystemDictionary_lock, THREAD); - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); - } - return NULL; - } + } // load_instance_class loop + + if (load_instance_added == true) { + // clean up placeholder entries for LOAD_INSTANCE success or error + // This brackets the SystemDictionary updates for both defining + // and initiating loaders + MutexLocker mu(SystemDictionary_lock, THREAD); + placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD); + SystemDictionary_lock->notify_all(); } } + if (HAS_PENDING_EXCEPTION || k.is_null()) { + return NULL; + } + #ifdef ASSERT { ClassLoaderData* loader_data = k->class_loader_data(); @@ -850,8 +837,8 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla // so we cannot allow GC to occur while we're holding this entry. // We're using a No_Safepoint_Verifier to catch any place where we // might potentially do a GC at all. - // SystemDictionary::do_unloading() asserts that classes are only - // unloaded at a safepoint. + // Dictionary::do_unloading() asserts that classes in SD are only + // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; if (dictionary()->is_valid_protection_domain(d_index, d_hash, name, loader_data, @@ -898,8 +885,8 @@ Klass* SystemDictionary::find(Symbol* class_name, // so we cannot allow GC to occur while we're holding this entry. // We're using a No_Safepoint_Verifier to catch any place where we // might potentially do a GC at all. - // SystemDictionary::do_unloading() asserts that classes are only - // unloaded at a safepoint. + // Dictionary::do_unloading() asserts that classes in SD are only + // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; return dictionary()->find(d_index, d_hash, class_name, loader_data, protection_domain, THREAD); @@ -965,10 +952,6 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name, // throw potential ClassFormatErrors. // // Note: "name" is updated. - // Further note: a placeholder will be added for this class when - // super classes are loaded (resolve_super_or_fail). We expect this - // to be called for all classes but java.lang.Object; and we preload - // java.lang.Object through resolve_or_fail, not this path. instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, loader_data, @@ -979,21 +962,6 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name, true, THREAD); - // We don't redefine the class, so we just need to clean up whether there - // was an error or not (don't want to modify any system dictionary - // data structures). - // Parsed name could be null if we threw an error before we got far - // enough along to parse it -- in that case, there is nothing to clean up. - if (parsed_name != NULL) { - unsigned int p_hash = placeholders()->compute_hash(parsed_name, - loader_data); - int p_index = placeholders()->hash_to_index(p_hash); - { - MutexLocker mu(SystemDictionary_lock, THREAD); - placeholders()->find_and_remove(p_index, p_hash, parsed_name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); - } - } if (host_klass.not_null() && k.not_null()) { assert(EnableInvokeDynamic, ""); @@ -1062,10 +1030,6 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, // throw potential ClassFormatErrors. // // Note: "name" is updated. - // Further note: a placeholder will be added for this class when - // super classes are loaded (resolve_super_or_fail). We expect this - // to be called for all classes but java.lang.Object; and we preload - // java.lang.Object through resolve_or_fail, not this path. instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, loader_data, @@ -1114,25 +1078,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, } } - // If parsing the class file or define_instance_class failed, we - // need to remove the placeholder added on our behalf. But we - // must make sure parsed_name is valid first (it won't be if we had - // a format error before the class was parsed far enough to - // find the name). - if (HAS_PENDING_EXCEPTION && parsed_name != NULL) { - unsigned int p_hash = placeholders()->compute_hash(parsed_name, - loader_data); - int p_index = placeholders()->hash_to_index(p_hash); - { - MutexLocker mu(SystemDictionary_lock, THREAD); - placeholders()->find_and_remove(p_index, p_hash, parsed_name, loader_data, THREAD); - SystemDictionary_lock->notify_all(); - } - return NULL; - } - - // Make sure that we didn't leave a place holder in the - // SystemDictionary; this is only done on success + // Make sure we have an entry in the SystemDictionary on success debug_only( { if (!HAS_PENDING_EXCEPTION) { assert(parsed_name != NULL, "parsed_name is still null?"); @@ -1547,8 +1493,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* clas // Other cases fall through, and may run into duplicate defines // caught by finding an entry in the SystemDictionary if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instance_klass() != NULL)) { - probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); - placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, THREAD); + placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD); SystemDictionary_lock->notify_all(); #ifdef ASSERT Klass* check = find_class(d_index, d_hash, name_h, loader_data); @@ -1578,8 +1523,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* clas probe->set_instance_klass(k()); } probe->set_definer(NULL); - probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); - placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, THREAD); + placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD); SystemDictionary_lock->notify_all(); } } @@ -1736,6 +1680,8 @@ int SystemDictionary::calculate_systemdictionary_size(int classcount) { } return newsize; } +// Assumes classes in the SystemDictionary are only unloaded at a safepoint +// Note: anonymous classes are not in the SD. bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { // First, mark for unload all ClassLoaderData referencing a dead class loader. bool has_dead_loaders = ClassLoaderDataGraph::do_unloading(is_alive); @@ -2105,9 +2051,7 @@ void SystemDictionary::update_dictionary(int d_index, unsigned int d_hash, // All loaded classes get a unique ID. TRACE_INIT_ID(k); - // Check for a placeholder. If there, remove it and make a - // new system dictionary entry. - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, THREAD); + // Make a new system dictionary entry. Klass* sd_check = find_class(d_index, d_hash, name, loader_data); if (sd_check == NULL) { dictionary()->add_klass(name, loader_data, k); @@ -2116,12 +2060,8 @@ void SystemDictionary::update_dictionary(int d_index, unsigned int d_hash, #ifdef ASSERT sd_check = find_class(d_index, d_hash, name, loader_data); assert (sd_check != NULL, "should have entry in system dictionary"); -// Changed to allow PH to remain to complete class circularity checking -// while only one thread can define a class at one time, multiple -// classes can resolve the superclass for a class at one time, -// and the placeholder is used to track that -// Symbol* ph_check = find_placeholder(name, class_loader); -// assert (ph_check == NULL, "should not have a placeholder entry"); + // Note: there may be a placeholder entry: for circularity testing + // or for parallel defines #endif SystemDictionary_lock->notify_all(); } diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index e6168ceba2c..ad0d7d9fc44 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -194,7 +194,10 @@ template(java_lang_VirtualMachineError, "java/lang/VirtualMachineError") \ template(java_lang_StackOverflowError, "java/lang/StackOverflowError") \ template(java_lang_StackTraceElement, "java/lang/StackTraceElement") \ + \ + /* Concurrency support */ \ template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ + template(sun_misc_Contended_signature, "Lsun/misc/Contended;") \ \ /* class symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, template, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -284,7 +287,7 @@ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \ - \ + \ /* common method and field names */ \ template(object_initializer_name, "") \ template(class_initializer_name, "") \ @@ -383,7 +386,6 @@ template(basicType_name, "basicType") \ template(append_name, "append") \ template(klass_name, "klass") \ - template(resolved_constructor_name, "resolved_constructor") \ template(array_klass_name, "array_klass") \ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ @@ -733,6 +735,11 @@ do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \ do_name( checkIndex_name, "checkIndex") \ \ + do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \ + do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \ + do_name( encodeISOArray_name, "encodeISOArray") \ + do_signature(encodeISOArray_signature, "([CI[BII)I") \ + \ /* java/lang/ref/Reference */ \ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ \ diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index c40a377ebb3..d5b8f8f9a78 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -30,6 +30,7 @@ #include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "code/pcDesc.hpp" +#include "compiler/compileBroker.hpp" #include "gc_implementation/shared/markSweep.hpp" #include "memory/allocation.inline.hpp" #include "memory/gcLocker.hpp" @@ -39,6 +40,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/arguments.hpp" #include "runtime/icache.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" @@ -168,6 +170,8 @@ nmethod* CodeCache::next_nmethod (CodeBlob* cb) { return (nmethod*)cb; } +static size_t maxCodeCacheUsed = 0; + CodeBlob* CodeCache::allocate(int size) { // Do not seize the CodeCache lock here--if the caller has not // already done so, we are going to lose bigtime, since the code @@ -192,6 +196,8 @@ CodeBlob* CodeCache::allocate(int size) { (address)_heap->end() - (address)_heap->begin()); } } + maxCodeCacheUsed = MAX2(maxCodeCacheUsed, ((address)_heap->high_boundary() - + (address)_heap->low_boundary()) - unallocated_capacity()); verify_if_often(); print_trace("allocation", cb, size); return cb; @@ -928,7 +934,14 @@ void CodeCache::print_internals() { FREE_C_HEAP_ARRAY(int, buckets, mtCode); } +#endif // !PRODUCT + void CodeCache::print() { + print_summary(tty); + +#ifndef PRODUCT + if (!Verbose) return; + CodeBlob_sizes live; CodeBlob_sizes dead; @@ -953,7 +966,7 @@ void CodeCache::print() { } - if (Verbose) { + if (WizardMode) { // print the oop_map usage int code_size = 0; int number_of_blobs = 0; @@ -977,20 +990,30 @@ void CodeCache::print() { tty->print_cr(" map size = %d", map_size); } +#endif // !PRODUCT } -#endif // PRODUCT +void CodeCache::print_summary(outputStream* st, bool detailed) { + size_t total = (_heap->high_boundary() - _heap->low_boundary()); + st->print_cr("CodeCache: size=" SIZE_FORMAT "Kb used=" SIZE_FORMAT + "Kb max_used=" SIZE_FORMAT "Kb free=" SIZE_FORMAT + "Kb max_free_chunk=" SIZE_FORMAT "Kb", + total/K, (total - unallocated_capacity())/K, + maxCodeCacheUsed/K, unallocated_capacity()/K, largest_free_block()/K); -void CodeCache::print_bounds(outputStream* st) { - st->print_cr("Code Cache [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", - _heap->low_boundary(), - _heap->high(), - _heap->high_boundary()); - st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT - " adapters=" UINT32_FORMAT " free_code_cache=" SIZE_FORMAT "Kb" - " largest_free_block=" SIZE_FORMAT, - nof_blobs(), nof_nmethods(), nof_adapters(), - unallocated_capacity()/K, largest_free_block()); + if (detailed) { + st->print_cr(" bounds [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT "]", + _heap->low_boundary(), + _heap->high(), + _heap->high_boundary()); + st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT + " adapters=" UINT32_FORMAT, + nof_blobs(), nof_nmethods(), nof_adapters()); + st->print_cr(" compilation: %s", CompileBroker::should_compile_new_jobs() ? + "enabled" : Arguments::mode() == Arguments::_int ? + "disabled (interpreter mode)" : + "disabled (not enough contiguous free space left)"); + } } void CodeCache::log_state(outputStream* st) { diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 6187ba9a2a7..92ce241b938 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -145,11 +145,11 @@ class CodeCache : AllStatic { static void prune_scavenge_root_nmethods(); // Printing/debugging - static void print() PRODUCT_RETURN; // prints summary + static void print(); // prints summary static void print_internals(); static void verify(); // verifies the code cache static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; - static void print_bounds(outputStream* st); // Prints a summary of the bounds of the code cache + static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage static void log_state(outputStream* st); // The full limits of the codeCache diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.hpp b/hotspot/src/share/vm/compiler/abstractCompiler.hpp index 9007a82fc49..96453e7d9ba 100644 --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp @@ -50,6 +50,7 @@ class AbstractCompiler : public CHeapObj { // Missing feature tests virtual bool supports_native() { return true; } virtual bool supports_osr () { return true; } + virtual bool can_compile_method(methodHandle method) { return true; } #if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK)) virtual bool is_c1 () { return false; } virtual bool is_c2 () { return false; } diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 73ab865dc74..41883d1b44d 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -1218,7 +1218,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, // lock, make sure that the compilation // isn't prohibited in a straightforward way. - if (compiler(comp_level) == NULL || compilation_is_prohibited(method, osr_bci, comp_level)) { + if (compiler(comp_level) == NULL || !compiler(comp_level)->can_compile_method(method) || compilation_is_prohibited(method, osr_bci, comp_level)) { return NULL; } @@ -1714,6 +1714,20 @@ void CompileBroker::maybe_block() { } } +// wrapper for CodeCache::print_summary() +static void codecache_print(bool detailed) +{ + ResourceMark rm; + stringStream s; + // Dump code cache into a buffer before locking the tty, + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print_summary(&s, detailed); + } + ttyLocker ttyl; + tty->print_cr(s.as_string()); +} + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1841,6 +1855,9 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, (int)time.milliseconds(), task->num_inlined_bytecodes()); } + if (PrintCodeCacheOnCompilation) + codecache_print(/* detailed= */ false); + // Disable compilation, if required. switch (compilable) { case ciEnv::MethodCompilable_never: @@ -1885,6 +1902,7 @@ void CompileBroker::handle_full_code_cache() { UseInterpreter = true; if (UseCompiler || AlwaysCompileLoopMethods ) { if (xtty != NULL) { + ResourceMark rm; stringStream s; // Dump code cache state into a buffer before locking the tty, // because log_state() will use locks causing lock conflicts. @@ -1898,9 +1916,9 @@ void CompileBroker::handle_full_code_cache() { } warning("CodeCache is full. Compiler has been disabled."); warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize="); - CodeCache::print_bounds(tty); #ifndef PRODUCT if (CompileTheWorld || ExitOnFullCodeCache) { + codecache_print(/* detailed= */ true); before_exit(JavaThread::current()); exit_globals(); // will delete tty vm_direct_exit(CompileTheWorld ? 0 : 1); @@ -1913,6 +1931,7 @@ void CompileBroker::handle_full_code_cache() { AlwaysCompileLoopMethods = false; } } + codecache_print(/* detailed= */ true); } // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/compiler/oopMap.cpp b/hotspot/src/share/vm/compiler/oopMap.cpp index 7c51c669b5c..8e6834c710d 100644 --- a/hotspot/src/share/vm/compiler/oopMap.cpp +++ b/hotspot/src/share/vm/compiler/oopMap.cpp @@ -542,17 +542,17 @@ void print_register_type(OopMapValue::oop_types x, VMReg optional, st->print("Oop"); break; case OopMapValue::value_value: - st->print("Value" ); + st->print("Value"); break; case OopMapValue::narrowoop_value: - tty->print("NarrowOop" ); + st->print("NarrowOop"); break; case OopMapValue::callee_saved_value: - st->print("Callers_" ); + st->print("Callers_"); optional->print_on(st); break; case OopMapValue::derived_oop_value: - st->print("Derived_oop_" ); + st->print("Derived_oop_"); optional->print_on(st); break; default: diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 45e53170859..78d956ff11d 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -554,7 +554,7 @@ void CompactibleFreeListSpace::reportFreeListStatistics() const { reportIndexedFreeListStatistics(); size_t total_size = totalSizeInIndexedFreeLists() + _dictionary->total_chunk_size(DEBUG_ONLY(freelistLock())); - gclog_or_tty->print(" free=%ld frag=%1.4f\n", total_size, flsFrag()); + gclog_or_tty->print(" free=" SIZE_FORMAT " frag=%1.4f\n", total_size, flsFrag()); } } diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 25b936fd8a9..6c1de182b74 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -3338,7 +3338,7 @@ bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) { if (Verbose && PrintGC) { size_t new_mem_size = _virtual_space.committed_size(); size_t old_mem_size = new_mem_size - bytes; - gclog_or_tty->print_cr("Expanding %s from %ldK by %ldK to %ldK", + gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", name(), old_mem_size/K, bytes/K, new_mem_size/K); } } @@ -9203,7 +9203,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) { if (Verbose && PrintGCDetails) { size_t new_mem_size = _virtual_space.committed_size(); size_t old_mem_size = new_mem_size + bytes; - gclog_or_tty->print_cr("Shrinking %s from %ldK by %ldK to %ldK", + gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", name(), old_mem_size/K, bytes/K, new_mem_size/K); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 7a102cf43d7..9782b67c007 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -131,17 +131,23 @@ void WorkerDataArray::print(int level, const char* title) { #ifndef PRODUCT +template <> const int WorkerDataArray::_uninitialized = -1; +template <> const double WorkerDataArray::_uninitialized = -1.0; +template <> const size_t WorkerDataArray::_uninitialized = (size_t)-1; + template void WorkerDataArray::reset() { for (uint i = 0; i < _length; i++) { - _data[i] = (T)-1; + _data[i] = (T)_uninitialized; } } template void WorkerDataArray::verify() { for (uint i = 0; i < _length; i++) { - assert(_data[i] >= (T)0, err_msg("Invalid data for worker %d", i)); + assert(_data[i] != _uninitialized, + err_msg("Invalid data for worker " UINT32_FORMAT ", data: %lf, uninitialized: %lf", + i, (double)_data[i], (double)_uninitialized)); } } @@ -201,20 +207,20 @@ void G1GCPhaseTimes::note_gc_end() { _last_termination_attempts.verify(); _last_gc_worker_end_times_ms.verify(); - for (uint i = 0; i < _active_gc_threads; i++) { - double worker_time = _last_gc_worker_end_times_ms.get(i) - _last_gc_worker_start_times_ms.get(i); - _last_gc_worker_times_ms.set(i, worker_time); + for (uint i = 0; i < _active_gc_threads; i++) { + double worker_time = _last_gc_worker_end_times_ms.get(i) - _last_gc_worker_start_times_ms.get(i); + _last_gc_worker_times_ms.set(i, worker_time); - double worker_known_time = _last_ext_root_scan_times_ms.get(i) + - _last_satb_filtering_times_ms.get(i) + - _last_update_rs_times_ms.get(i) + - _last_scan_rs_times_ms.get(i) + - _last_obj_copy_times_ms.get(i) + - _last_termination_times_ms.get(i); + double worker_known_time = _last_ext_root_scan_times_ms.get(i) + + _last_satb_filtering_times_ms.get(i) + + _last_update_rs_times_ms.get(i) + + _last_scan_rs_times_ms.get(i) + + _last_obj_copy_times_ms.get(i) + + _last_termination_times_ms.get(i); - double worker_other_time = worker_time - worker_known_time; - _last_gc_worker_other_times_ms.set(i, worker_other_time); - } + double worker_other_time = worker_time - worker_known_time; + _last_gc_worker_other_times_ms.set(i, worker_other_time); + } _last_gc_worker_times_ms.verify(); _last_gc_worker_other_times_ms.verify(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index 99e35c63d43..b6e289ed22a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -35,6 +35,8 @@ class WorkerDataArray : public CHeapObj { const char* _print_format; bool _print_sum; + NOT_PRODUCT(static const T _uninitialized;) + // We are caching the sum and average to only have to calculate them once. // This is not done in an MT-safe way. It is intetened to allow single // threaded code to call sum() and average() multiple times in any order diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 92b1cb3fc49..d362956ea80 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -287,24 +287,24 @@ "The number of times we'll force an overflow during " \ "concurrent marking") \ \ - experimental(uintx, G1NewSizePercent, 20, \ + experimental(uintx, G1NewSizePercent, 5, \ "Percentage (0-100) of the heap size to use as default " \ "minimum young gen size.") \ \ - experimental(uintx, G1MaxNewSizePercent, 80, \ + experimental(uintx, G1MaxNewSizePercent, 60, \ "Percentage (0-100) of the heap size to use as default " \ " maximum young gen size.") \ \ - experimental(uintx, G1MixedGCLiveThresholdPercent, 90, \ + experimental(uintx, G1MixedGCLiveThresholdPercent, 65, \ "Threshold for regions to be considered for inclusion in the " \ "collection set of mixed GCs. " \ "Regions with live bytes exceeding this will not be collected.") \ \ - product(uintx, G1HeapWastePercent, 5, \ + product(uintx, G1HeapWastePercent, 10, \ "Amount of space, expressed as a percentage of the heap size, " \ "that G1 is willing not to collect to avoid expensive GCs.") \ \ - product(uintx, G1MixedGCCountTarget, 4, \ + product(uintx, G1MixedGCCountTarget, 8, \ "The target number of mixed GCs after a marking cycle.") \ \ experimental(uintx, G1OldCSetRegionThresholdPercent, 10, \ diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index 273322436ba..e868d870990 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -878,12 +878,6 @@ void EvacuateFollowersClosureGeneral::do_void() { bool ParNewGeneration::_avoid_promotion_undo = false; -void ParNewGeneration::adjust_desired_tenuring_threshold() { - // Set the desired survivor size to half the real survivor space - _tenuring_threshold = - age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); -} - // A Generation that does parallel young-gen collection. void ParNewGeneration::collect(bool full, @@ -1013,6 +1007,8 @@ void ParNewGeneration::collect(bool full, size_policy->reset_gc_overhead_limit_count(); assert(to()->is_empty(), "to space should be empty now"); + + adjust_desired_tenuring_threshold(); } else { assert(_promo_failure_scan_stack.is_empty(), "post condition"); _promo_failure_scan_stack.clear(true); // Clear cached segments. @@ -1035,7 +1031,6 @@ void ParNewGeneration::collect(bool full, from()->set_concurrent_iteration_safe_limit(from()->top()); to()->set_concurrent_iteration_safe_limit(to()->top()); - adjust_desired_tenuring_threshold(); if (ResizePLAB) { plab_stats()->adjust_desired_plab_sz(n_workers); } diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index bbb6176fd08..487552bfba9 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -347,10 +347,6 @@ class ParNewGeneration: public DefNewGeneration { bool survivor_overflow() { return _survivor_overflow; } void set_survivor_overflow(bool v) { _survivor_overflow = v; } - // Adjust the tenuring threshold. See the implementation for - // the details of the policy. - virtual void adjust_desired_tenuring_threshold(); - public: ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index f68b1b5a446..078bd62aff7 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -529,7 +529,7 @@ bool PSScavenge::invoke_no_policy() { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size %ld bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", size_policy->calculated_survivor_size_in_bytes(), _tenuring_threshold, MaxTenuringThreshold); } diff --git a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp index 50162a0adb1..311fd7771dd 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp @@ -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 @@ -96,7 +96,7 @@ uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size %ld bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", desired_survivor_size*oopSize, result, MaxTenuringThreshold); } diff --git a/hotspot/src/share/vm/memory/defNewGeneration.cpp b/hotspot/src/share/vm/memory/defNewGeneration.cpp index cca7cd0e704..689ce7b8bbf 100644 --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp @@ -550,6 +550,11 @@ HeapWord* DefNewGeneration::expand_and_allocate(size_t size, return allocate(size, is_tlab); } +void DefNewGeneration::adjust_desired_tenuring_threshold() { + // Set the desired survivor size to half the real survivor space + _tenuring_threshold = + age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); +} void DefNewGeneration::collect(bool full, bool clear_all_soft_refs, @@ -649,9 +654,7 @@ void DefNewGeneration::collect(bool full, assert(to()->is_empty(), "to space should be empty now"); - // Set the desired survivor size to half the real survivor space - _tenuring_threshold = - age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); + adjust_desired_tenuring_threshold(); // A successful scavenge should restart the GC time limit count which is // for full GC's. diff --git a/hotspot/src/share/vm/memory/defNewGeneration.hpp b/hotspot/src/share/vm/memory/defNewGeneration.hpp index b7c794d86c2..38ea742b38a 100644 --- a/hotspot/src/share/vm/memory/defNewGeneration.hpp +++ b/hotspot/src/share/vm/memory/defNewGeneration.hpp @@ -124,7 +124,9 @@ protected: _should_allocate_from_space = true; } - protected: + // Tenuring + void adjust_desired_tenuring_threshold(); + // Spaces EdenSpace* _eden_space; ContiguousSpace* _from_space; diff --git a/hotspot/src/share/vm/memory/metadataFactory.hpp b/hotspot/src/share/vm/memory/metadataFactory.hpp index 3c4689c479a..fce8d9b34d7 100644 --- a/hotspot/src/share/vm/memory/metadataFactory.hpp +++ b/hotspot/src/share/vm/memory/metadataFactory.hpp @@ -66,7 +66,11 @@ class MetadataFactory : AllStatic { if (data != NULL) { assert(loader_data != NULL, "shouldn't pass null"); int size = data->size(); - loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size, false); + if (DumpSharedSpaces) { + loader_data->ro_metaspace()->deallocate((MetaWord*)data, size, false); + } else { + loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size, false); + } } } @@ -77,6 +81,7 @@ class MetadataFactory : AllStatic { assert(loader_data != NULL, "shouldn't pass null"); int size = md->size(); // Call metadata's deallocate function which will call deallocate fields + assert(!DumpSharedSpaces, "cannot deallocate metadata when dumping CDS archive"); assert(!md->on_stack(), "can't deallocate things on stack"); md->deallocate_contents(loader_data); loader_data->metaspace_non_null()->deallocate((MetaWord*)md, size, md->is_klass()); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 5954e43d05a..4f53114c6cd 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -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 @@ -373,17 +373,44 @@ void VM_PopulateDumpSharedSpace::doit() { md_top = wc.get_top(); // Print shared spaces all the time - const char* fmt = "%s space: " PTR_FORMAT " out of " PTR_FORMAT " words allocated at " PTR_FORMAT "."; + const char* fmt = "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " PTR_FORMAT; Metaspace* ro_space = _loader_data->ro_metaspace(); Metaspace* rw_space = _loader_data->rw_metaspace(); - tty->print_cr(fmt, "ro", ro_space->used_words(Metaspace::NonClassType), - ro_space->capacity_words(Metaspace::NonClassType), - ro_space->bottom()); - tty->print_cr(fmt, "rw", rw_space->used_words(Metaspace::NonClassType), - rw_space->capacity_words(Metaspace::NonClassType), - rw_space->bottom()); - tty->print_cr(fmt, "md", md_top - md_low, md_end-md_low, md_low); - tty->print_cr(fmt, "mc", mc_top - mc_low, mc_end-mc_low, mc_low); + const size_t BPW = BytesPerWord; + + // Allocated size of each space (may not be all occupied) + const size_t ro_alloced = ro_space->capacity_words(Metaspace::NonClassType) * BPW; + const size_t rw_alloced = rw_space->capacity_words(Metaspace::NonClassType) * BPW; + const size_t md_alloced = md_end-md_low; + const size_t mc_alloced = mc_end-mc_low; + const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced; + + // Occupied size of each space. + const size_t ro_bytes = ro_space->used_words(Metaspace::NonClassType) * BPW; + const size_t rw_bytes = rw_space->used_words(Metaspace::NonClassType) * BPW; + const size_t md_bytes = size_t(md_top - md_low); + const size_t mc_bytes = size_t(mc_top - mc_low); + + // Percent of total size + const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes; + const double ro_t_perc = ro_bytes / double(total_bytes) * 100.0; + const double rw_t_perc = rw_bytes / double(total_bytes) * 100.0; + const double md_t_perc = md_bytes / double(total_bytes) * 100.0; + const double mc_t_perc = mc_bytes / double(total_bytes) * 100.0; + + // Percent of fullness of each space + const double ro_u_perc = ro_bytes / double(ro_alloced) * 100.0; + const double rw_u_perc = rw_bytes / double(rw_alloced) * 100.0; + const double md_u_perc = md_bytes / double(md_alloced) * 100.0; + const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0; + const double total_u_perc = total_bytes / double(total_alloced) * 100.0; + + tty->print_cr(fmt, "ro", ro_bytes, ro_t_perc, ro_alloced, ro_u_perc, ro_space->bottom()); + tty->print_cr(fmt, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, rw_space->bottom()); + tty->print_cr(fmt, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, md_low); + tty->print_cr(fmt, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, mc_low); + tty->print_cr("total : %9d [100.0%% of total] out of %9d bytes [%4.1f%% used]", + total_bytes, total_alloced, total_u_perc); // Update the vtable pointers in all of the Klass objects in the // heap. They should point to newly generated vtable. diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index c528d270c64..c9199228cb9 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -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 @@ -228,7 +228,7 @@ void Universe::check_alignment(uintx size, uintx alignment, const char* name) { if (size < alignment || size % alignment != 0) { ResourceMark rm; stringStream st; - st.print("Size of %s (%ld bytes) must be aligned to %ld bytes", name, size, alignment); + st.print("Size of %s (" UINTX_FORMAT " bytes) must be aligned to " UINTX_FORMAT " bytes", name, size, alignment); char* error = st.as_string(); vm_exit_during_initialization(error); } diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 08c650278e6..8b593982140 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -122,7 +122,12 @@ class ExceptionTableElement VALUE_OBJ_CLASS_SPEC { class MethodParametersElement VALUE_OBJ_CLASS_SPEC { public: u2 name_cp_index; - u4 flags; + // This has to happen, otherwise it will cause SIGBUS from a + // misaligned u4 on some architectures (ie SPARC) + // because MethodParametersElements are only aligned mod 2 + // within the ConstMethod container u2 flags_hi; + u2 flags_hi; + u2 flags_lo; }; diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index ff8472d3d79..770510c7880 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -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 @@ -66,7 +66,7 @@ ConstantPool::ConstantPool(Array* tags) { set_pool_holder(NULL); set_flags(0); // only set to non-zero if constant pool is merged by RedefineClasses - set_orig_length(0); + set_version(0); set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock")); // all fields are initialized; needed for GC set_on_stack(false); diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 768cd39a65c..65546021553 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -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 @@ -103,8 +103,8 @@ class ConstantPool : public Metadata { union { // set for CDS to restore resolved references int _resolved_reference_length; - // only set to non-zero if constant pool is merged by RedefineClasses - int _orig_length; + // keeps version number for redefined classes (used in backtrace) + int _version; } _saved; Monitor* _lock; @@ -784,8 +784,11 @@ class ConstantPool : public Metadata { static void copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS); static void copy_entry_to(constantPoolHandle from_cp, int from_i, constantPoolHandle to_cp, int to_i, TRAPS); int find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS); - int orig_length() const { return _saved._orig_length; } - void set_orig_length(int orig_length) { _saved._orig_length = orig_length; } + int version() const { return _saved._version; } + void set_version(int version) { _saved._version = version; } + void increment_and_save_version(int version) { + _saved._version = version >= 0 ? (version + 1) : version; // keep overflow + } void set_resolved_reference_length(int length) { _saved._resolved_reference_length = length; } int resolved_reference_length() const { return _saved._resolved_reference_length; } diff --git a/hotspot/src/share/vm/oops/fieldInfo.hpp b/hotspot/src/share/vm/oops/fieldInfo.hpp index ee4af47204d..331dc05f37c 100644 --- a/hotspot/src/share/vm/oops/fieldInfo.hpp +++ b/hotspot/src/share/vm/oops/fieldInfo.hpp @@ -43,14 +43,29 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { public: // fields // Field info extracted from the class file and stored - // as an array of 7 shorts + // as an array of 6 shorts. + +#define FIELDINFO_TAG_SIZE 2 +#define FIELDINFO_TAG_BLANK 0 +#define FIELDINFO_TAG_OFFSET 1 +#define FIELDINFO_TAG_TYPE_PLAIN 2 +#define FIELDINFO_TAG_TYPE_CONTENDED 3 +#define FIELDINFO_TAG_MASK 3 + + // Packed field has the tag, and can be either of: + // hi bits <--------------------------- lo bits + // |---------high---------|---------low---------| + // ..........................................00 - blank + // [------------------offset----------------]01 - real field offset + // ......................[-------type-------]10 - plain field with type + // [--contention_group--][-------type-------]11 - contended field with type and contention group enum FieldOffset { access_flags_offset = 0, name_index_offset = 1, signature_index_offset = 2, initval_index_offset = 3, - low_offset = 4, - high_offset = 5, + low_packed_offset = 4, + high_packed_offset = 5, field_slots = 6 }; @@ -76,17 +91,90 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { void initialize(u2 access_flags, u2 name_index, u2 signature_index, - u2 initval_index, - u4 offset) { + u2 initval_index) { _shorts[access_flags_offset] = access_flags; _shorts[name_index_offset] = name_index; _shorts[signature_index_offset] = signature_index; _shorts[initval_index_offset] = initval_index; - set_offset(offset); + _shorts[low_packed_offset] = 0; + _shorts[high_packed_offset] = 0; } u2 access_flags() const { return _shorts[access_flags_offset]; } - u4 offset() const { return build_int_from_shorts(_shorts[low_offset], _shorts[high_offset]); } + u4 offset() const { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_OFFSET: + return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE; +#ifndef PRODUCT + case FIELDINFO_TAG_TYPE_PLAIN: + ShouldNotReachHere2("Asking offset for the plain type field"); + case FIELDINFO_TAG_TYPE_CONTENDED: + ShouldNotReachHere2("Asking offset for the contended type field"); + case FIELDINFO_TAG_BLANK: + ShouldNotReachHere2("Asking offset for the blank field"); +#endif + } + ShouldNotReachHere(); + return 0; + } + + bool is_contended() const { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_TYPE_PLAIN: + return false; + case FIELDINFO_TAG_TYPE_CONTENDED: + return true; +#ifndef PRODUCT + case FIELDINFO_TAG_OFFSET: + ShouldNotReachHere2("Asking contended flag for the field with offset"); + case FIELDINFO_TAG_BLANK: + ShouldNotReachHere2("Asking contended flag for the blank field"); +#endif + } + ShouldNotReachHere(); + return false; + } + + u2 contended_group() const { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_TYPE_PLAIN: + return 0; + case FIELDINFO_TAG_TYPE_CONTENDED: + return _shorts[high_packed_offset]; +#ifndef PRODUCT + case FIELDINFO_TAG_OFFSET: + ShouldNotReachHere2("Asking the contended group for the field with offset"); + case FIELDINFO_TAG_BLANK: + ShouldNotReachHere2("Asking the contended group for the blank field"); +#endif + } + ShouldNotReachHere(); + return 0; + } + + u2 allocation_type() const { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_TYPE_PLAIN: + case FIELDINFO_TAG_TYPE_CONTENDED: + return (lo >> FIELDINFO_TAG_SIZE); +#ifndef PRODUCT + case FIELDINFO_TAG_OFFSET: + ShouldNotReachHere2("Asking the field type for field with offset"); + case FIELDINFO_TAG_BLANK: + ShouldNotReachHere2("Asking the field type for the blank field"); +#endif + } + ShouldNotReachHere(); + return 0; + } + + bool is_offset_set() const { + return (_shorts[low_packed_offset] & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET; + } Symbol* name(constantPoolHandle cp) const { int index = name_index(); @@ -106,8 +194,46 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { void set_access_flags(u2 val) { _shorts[access_flags_offset] = val; } void set_offset(u4 val) { - _shorts[low_offset] = extract_low_short_from_int(val); - _shorts[high_offset] = extract_high_short_from_int(val); + val = val << FIELDINFO_TAG_SIZE; // make room for tag + _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET; + _shorts[high_packed_offset] = extract_high_short_from_int(val); + } + + void set_allocation_type(int type) { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_BLANK: + _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF; + _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK; + _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN; + return; +#ifndef PRODUCT + case FIELDINFO_TAG_TYPE_PLAIN: + case FIELDINFO_TAG_TYPE_CONTENDED: + case FIELDINFO_TAG_OFFSET: + ShouldNotReachHere2("Setting the field type with overwriting"); +#endif + } + ShouldNotReachHere(); + } + + void set_contended_group(u2 val) { + u2 lo = _shorts[low_packed_offset]; + switch(lo & FIELDINFO_TAG_MASK) { + case FIELDINFO_TAG_TYPE_PLAIN: + _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_CONTENDED; + _shorts[high_packed_offset] = val; + return; +#ifndef PRODUCT + case FIELDINFO_TAG_TYPE_CONTENDED: + ShouldNotReachHere2("Overwriting contended group"); + case FIELDINFO_TAG_BLANK: + ShouldNotReachHere2("Setting contended group for the blank field"); + case FIELDINFO_TAG_OFFSET: + ShouldNotReachHere2("Setting contended group for field with offset"); +#endif + } + ShouldNotReachHere(); } bool is_internal() const { diff --git a/hotspot/src/share/vm/oops/fieldStreams.hpp b/hotspot/src/share/vm/oops/fieldStreams.hpp index adde764127b..acc590c970c 100644 --- a/hotspot/src/share/vm/oops/fieldStreams.hpp +++ b/hotspot/src/share/vm/oops/fieldStreams.hpp @@ -160,9 +160,26 @@ class FieldStreamBase : public StackObj { return field()->offset(); } + int allocation_type() const { + return field()->allocation_type(); + } + void set_offset(int offset) { field()->set_offset(offset); } + + bool is_offset_set() const { + return field()->is_offset_set(); + } + + bool is_contended() const { + return field()->is_contended(); + } + + int contended_group() const { + return field()->contended_group(); + } + }; // Iterate over only the internal fields diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index d123641a0c7..b0b7038e35b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -2890,11 +2890,7 @@ void InstanceKlass::oop_print_on(oop obj, outputStream* st) { st->print(BULLET"fake entry for mirror: "); mirrored_klass->print_value_on_maybe_null(st); st->cr(); - st->print(BULLET"fake entry resolved_constructor: "); - Method* ctor = java_lang_Class::resolved_constructor(obj); - ctor->print_value_on_maybe_null(st); Klass* array_klass = java_lang_Class::array_klass(obj); - st->cr(); st->print(BULLET"fake entry for array: "); array_klass->print_value_on_maybe_null(st); st->cr(); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 0d173faa510..97b3dd23313 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -225,12 +225,17 @@ class InstanceKlass: public Klass { u2 _java_fields_count; // The number of declared Java fields int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks + // _is_marked_dependent can be set concurrently, thus cannot be part of the + // _misc_flags. bool _is_marked_dependent; // used for marking during flushing and deoptimization + enum { _misc_rewritten = 1 << 0, // methods rewritten. _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops _misc_should_verify_class = 1 << 2, // allow caching of preverification - _misc_is_anonymous = 1 << 3 // has embedded _inner_classes field + _misc_is_anonymous = 1 << 3, // has embedded _inner_classes field + _misc_is_contended = 1 << 4, // marked with contended annotation + _misc_has_default_methods = 1 << 5 // class/superclass/implemented interfaces has default methods }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -253,10 +258,6 @@ class InstanceKlass: public Klass { jint _cached_class_file_len; // JVMTI: length of above JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration - // true if class, superclass, or implemented interfaces have default methods - bool _has_default_methods; - - volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change // Method array. Array* _methods; // Interface (Klass*s) this class declares locally to implement. @@ -280,6 +281,8 @@ class InstanceKlass: public Klass { // ... Array* _fields; + volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change + // Class states are defined as ClassState (see above). // Place the _init_state here to utilize the unused 2-byte after // _idnum_allocated_count. @@ -550,6 +553,17 @@ class InstanceKlass: public Klass { return is_anonymous() ? java_mirror() : class_loader(); } + bool is_contended() const { + return (_misc_flags & _misc_is_contended) != 0; + } + void set_is_contended(bool value) { + if (value) { + _misc_flags |= _misc_is_contended; + } else { + _misc_flags &= ~_misc_is_contended; + } + } + // signers objArrayOop signers() const { return _signers; } void set_signers(objArrayOop s) { klass_oop_store((oop*)&_signers, s); } @@ -616,8 +630,16 @@ class InstanceKlass: public Klass { return _jvmti_cached_class_field_map; } - bool has_default_methods() const { return _has_default_methods; } - void set_has_default_methods(bool b) { _has_default_methods = b; } + bool has_default_methods() const { + return (_misc_flags & _misc_has_default_methods) != 0; + } + void set_has_default_methods(bool b) { + if (b) { + _misc_flags |= _misc_has_default_methods; + } else { + _misc_flags &= ~_misc_has_default_methods; + } + } // for adding methods, ConstMethod::UNSET_IDNUM means no more ids available inline u2 next_method_idnum(); diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index fa481caae22..e1891226189 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -516,6 +516,9 @@ develop(bool, SpecialArraysEquals, true, \ "special version of Arrays.equals(char[],char[])") \ \ + product(bool, SpecialEncodeISOArray, true, \ + "special version of ISO_8859_1$Encoder.encodeISOArray") \ + \ develop(bool, BailoutToInterpreterForThrows, false, \ "Compiled methods which throws/catches exceptions will be " \ "deopt and intp.") \ diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index e8c23b38e33..c90b76d4adb 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -165,13 +165,13 @@ uint ReturnNode::match_edge(uint idx) const { #ifndef PRODUCT -void ReturnNode::dump_req() const { +void ReturnNode::dump_req(outputStream *st) const { // Dump the required inputs, enclosed in '(' and ')' uint i; // Exit value of loop - for( i=0; iprint("returns"); - if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); - else tty->print("_ "); + for (i = 0; i < req(); i++) { // For all required inputs + if (i == TypeFunc::Parms) st->print("returns"); + if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); + else st->print("_ "); } } #endif @@ -208,13 +208,13 @@ uint RethrowNode::match_edge(uint idx) const { } #ifndef PRODUCT -void RethrowNode::dump_req() const { +void RethrowNode::dump_req(outputStream *st) const { // Dump the required inputs, enclosed in '(' and ')' uint i; // Exit value of loop - for( i=0; iprint("exception"); - if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); - else tty->print("_ "); + for (i = 0; i < req(); i++) { // For all required inputs + if (i == TypeFunc::Parms) st->print("exception"); + if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); + else st->print("_ "); } } #endif @@ -330,7 +330,8 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c st->print(" %s%d]=#ScObj" INT32_FORMAT, msg, i, sco_n); return; } - if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined + if (regalloc->node_regs_max_index() > 0 && + OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined char buf[50]; regalloc->dump_register(n,buf); st->print(" %s%d]=%s",msg,i,buf); @@ -381,7 +382,7 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c //------------------------------format----------------------------------------- void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const { st->print(" #"); - if( _method ) { + if (_method) { _method->print_short_name(st); st->print(" @ bci:%d ",_bci); } else { @@ -393,21 +394,22 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) MachSafePointNode *mcall = n->as_MachSafePoint(); uint i; // Print locals - for( i = 0; i < (uint)loc_size(); i++ ) - format_helper( regalloc, st, mcall->local(this, i), "L[", i, &scobjs ); + for (i = 0; i < (uint)loc_size(); i++) + format_helper(regalloc, st, mcall->local(this, i), "L[", i, &scobjs); // Print stack for (i = 0; i < (uint)stk_size(); i++) { if ((uint)(_stkoff + i) >= mcall->len()) st->print(" oob "); else - format_helper( regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs ); + format_helper(regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs); } for (i = 0; (int)i < nof_monitors(); i++) { Node *box = mcall->monitor_box(this, i); Node *obj = mcall->monitor_obj(this, i); - if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) { + if (regalloc->node_regs_max_index() > 0 && + OptoReg::is_valid(regalloc->get_reg_first(box))) { box = BoxLockNode::box_node(box); - format_helper( regalloc, st, box, "MON-BOX[", i, &scobjs ); + format_helper(regalloc, st, box, "MON-BOX[", i, &scobjs); } else { OptoReg::Name box_reg = BoxLockNode::reg(box); st->print(" MON-BOX%d=%s+%d", @@ -420,7 +422,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) if (BoxLockNode::box_node(box)->is_eliminated()) obj_msg = "MON-OBJ(LOCK ELIMINATED)["; } - format_helper( regalloc, st, obj, obj_msg, i, &scobjs ); + format_helper(regalloc, st, obj, obj_msg, i, &scobjs); } for (i = 0; i < (uint)scobjs.length(); i++) { @@ -463,9 +465,9 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) st->print(" ["); cifield = iklass->nonstatic_field_at(0); cifield->print_name_on(st); - format_helper( regalloc, st, fld_node, ":", 0, &scobjs ); + format_helper(regalloc, st, fld_node, ":", 0, &scobjs); } else { - format_helper( regalloc, st, fld_node, "[", 0, &scobjs ); + format_helper(regalloc, st, fld_node, "[", 0, &scobjs); } for (uint j = 1; j < nf; j++) { fld_node = mcall->in(first_ind+j); @@ -473,9 +475,9 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) st->print(", ["); cifield = iklass->nonstatic_field_at(j); cifield->print_name_on(st); - format_helper( regalloc, st, fld_node, ":", j, &scobjs ); + format_helper(regalloc, st, fld_node, ":", j, &scobjs); } else { - format_helper( regalloc, st, fld_node, ", [", j, &scobjs ); + format_helper(regalloc, st, fld_node, ", [", j, &scobjs); } } } @@ -483,7 +485,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) } } st->print_cr(""); - if (caller() != NULL) caller()->format(regalloc, n, st); + if (caller() != NULL) caller()->format(regalloc, n, st); } @@ -586,15 +588,15 @@ JVMState* JVMState::clone_deep(Compile* C) const { uint CallNode::cmp( const Node &n ) const { return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; } #ifndef PRODUCT -void CallNode::dump_req() const { +void CallNode::dump_req(outputStream *st) const { // Dump the required inputs, enclosed in '(' and ')' uint i; // Exit value of loop - for( i=0; iprint("("); - if( in(i) ) tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); - else tty->print("_ "); + for (i = 0; i < req(); i++) { // For all required inputs + if (i == TypeFunc::Parms) st->print("("); + if (in(i)) st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); + else st->print("_ "); } - tty->print(")"); + st->print(")"); } void CallNode::dump_spec(outputStream *st) const { diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index fee091f798d..0aa35c214e5 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -126,7 +126,7 @@ public: virtual uint ideal_reg() const { return NotAMachineReg; } virtual uint match_edge(uint idx) const; #ifndef PRODUCT - virtual void dump_req() const; + virtual void dump_req(outputStream *st = tty) const; #endif }; @@ -147,7 +147,7 @@ class RethrowNode : public Node { virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return NotAMachineReg; } #ifndef PRODUCT - virtual void dump_req() const; + virtual void dump_req(outputStream *st = tty) const; #endif }; @@ -579,7 +579,7 @@ public: virtual uint match_edge(uint idx) const; #ifndef PRODUCT - virtual void dump_req() const; + virtual void dump_req(outputStream *st = tty) const; virtual void dump_spec(outputStream *st) const; #endif }; diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 3f726991dd0..f97b385f422 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -127,6 +127,7 @@ macro(DivL) macro(DivMod) macro(DivModI) macro(DivModL) +macro(EncodeISOArray) macro(EncodeP) macro(EncodePKlass) macro(ExpD) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index f090939186d..ae9d6996a9c 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -692,7 +692,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr PhaseGVN gvn(node_arena(), estimated_size); set_initial_gvn(&gvn); - if (PrintInlining) { + if (PrintInlining || PrintIntrinsics NOT_PRODUCT( || PrintOptoInlining)) { _print_inlining_list = new (comp_arena())GrowableArray(comp_arena(), 1, 1, PrintInliningBuffer()); } { // Scope for timing the parser @@ -2049,7 +2049,7 @@ void Compile::Optimize() { } // (End scope of igvn; run destructor if necessary for asserts.) - dump_inlining(); + dump_inlining(); // A method with only infinite loops has no edges entering loops from root { NOT_PRODUCT( TracePhase t2("graphReshape", &_t_graphReshaping, TimeCompiler); ) @@ -3497,7 +3497,7 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n } void Compile::dump_inlining() { - if (PrintInlining) { + if (PrintInlining || PrintIntrinsics NOT_PRODUCT( || PrintOptoInlining)) { // Print inlining message for candidates that we couldn't inline // for lack of space or non constant receiver for (int i = 0; i < _late_inlines.length(); i++) { diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index 5d094c99afc..9a7562d01fb 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -553,7 +553,13 @@ void Parse::do_call() { rtype = ctype; } } else { - assert(rtype == ctype, "mismatched return types"); // symbolic resolution enforces this + // Symbolic resolution enforces the types to be the same. + // NOTE: We must relax the assert for unloaded types because two + // different ciType instances of the same unloaded class type + // can appear to be "loaded" by different loaders (depending on + // the accessing class). + assert(!rtype->is_loaded() || !ctype->is_loaded() || rtype == ctype, + err_msg_res("mismatched return types: rtype=%s, ctype=%s", rtype->name(), ctype->name())); } // If the return type of the method is not loaded, assert that the diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 659828e509f..c5a93dfa68f 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -523,7 +523,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de case Op_AryEq: case Op_StrComp: case Op_StrEquals: - case Op_StrIndexOf: { + case Op_StrIndexOf: + case Op_EncodeISOArray: { add_local_var(n, PointsToNode::ArgEscape); delayed_worklist->push(n); // Process it later. break; @@ -701,7 +702,8 @@ void ConnectionGraph::add_final_edges(Node *n) { case Op_AryEq: case Op_StrComp: case Op_StrEquals: - case Op_StrIndexOf: { + case Op_StrIndexOf: + case Op_EncodeISOArray: { // char[] arrays passed to string intrinsic do not escape but // they are not scalar replaceable. Adjust escape state for them. // Start from in(2) edge since in(1) is memory edge. @@ -2581,15 +2583,22 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra } // Otherwise skip it (the call updated 'result' value). } else if (result->Opcode() == Op_SCMemProj) { - assert(result->in(0)->is_LoadStore(), "sanity"); - const Type *at = igvn->type(result->in(0)->in(MemNode::Address)); + Node* mem = result->in(0); + Node* adr = NULL; + if (mem->is_LoadStore()) { + adr = mem->in(MemNode::Address); + } else { + assert(mem->Opcode() == Op_EncodeISOArray, "sanity"); + adr = mem->in(3); // Memory edge corresponds to destination array + } + const Type *at = igvn->type(adr); if (at != Type::TOP) { assert (at->isa_ptr() != NULL, "pointer type required."); int idx = C->get_alias_index(at->is_ptr()); assert(idx != alias_idx, "Object is not scalar replaceable if a LoadStore node access its field"); break; } - result = result->in(0)->in(MemNode::Memory); + result = mem->in(MemNode::Memory); } } if (result->is_Phi()) { @@ -2927,6 +2936,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) if (m->is_MergeMem()) { assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist"); } + } else if (use->Opcode() == Op_EncodeISOArray) { + if (use->in(MemNode::Memory) == n || use->in(3) == n) { + // EncodeISOArray overwrites destination array + memnode_worklist.append_if_missing(use); + } } else { uint op = use->Opcode(); if (!(op == Op_CmpP || op == Op_Conv2B || @@ -2962,6 +2976,16 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) n = n->as_MemBar()->proj_out(TypeFunc::Memory); if (n == NULL) continue; + } else if (n->Opcode() == Op_EncodeISOArray) { + // get the memory projection + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node *use = n->fast_out(i); + if (use->Opcode() == Op_SCMemProj) { + n = use; + break; + } + } + assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } else { assert(n->is_Mem(), "memory node required."); Node *addr = n->in(MemNode::Address); @@ -2999,7 +3023,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) Node *use = n->fast_out(i); if (use->is_Phi() || use->is_ClearArray()) { memnode_worklist.append_if_missing(use); - } else if(use->is_Mem() && use->in(MemNode::Memory) == n) { + } else if (use->is_Mem() && use->in(MemNode::Memory) == n) { if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores continue; memnode_worklist.append_if_missing(use); @@ -3010,6 +3034,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) assert(use->in(MemNode::Memory) != n, "EA: missing memory path"); } else if (use->is_MergeMem()) { assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist"); + } else if (use->Opcode() == Op_EncodeISOArray) { + if (use->in(MemNode::Memory) == n || use->in(3) == n) { + // EncodeISOArray overwrites destination array + memnode_worklist.append_if_missing(use); + } } else { uint op = use->Opcode(); if (!(op == Op_StoreCM || diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 0928704d9cb..1f811b8f4b8 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -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 @@ -547,7 +547,7 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { // max. 2 chars allowed if (value >= -9 && value <= 99) { - sprintf(buffer, INT64_FORMAT, value); + sprintf(buffer, JLONG_FORMAT, value); print_prop(short_name, buffer); } else { print_prop(short_name, "L"); diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 5ca4bae13d7..35006ff23b4 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -175,6 +175,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe case Op_StrEquals: case Op_StrIndexOf: case Op_AryEq: + case Op_EncodeISOArray: // Not a legit memory op for implicit null check regardless of // embedded loads continue; diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 313339edfde..e3aee707e4a 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -290,6 +290,7 @@ class LibraryCallKit : public GraphKit { bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); + bool inline_encodeISOArray(); }; @@ -381,6 +382,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { // These also use the arraycopy intrinsic mechanism: if (!InlineArrayCopy) return NULL; break; + case vmIntrinsics::_encodeISOArray: + if (!SpecialEncodeISOArray) return NULL; + if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return NULL; + break; case vmIntrinsics::_checkIndex: // We do not intrinsify this. The optimizer does fine with it. return NULL; @@ -799,6 +804,9 @@ bool LibraryCallKit::try_to_inline() { case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: return inline_cipherBlockChaining_AESCrypt(intrinsic_id()); + case vmIntrinsics::_encodeISOArray: + return inline_encodeISOArray(); + default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -3559,7 +3567,6 @@ bool LibraryCallKit::inline_native_getLength() { // public static T[] java.util.Arrays.copyOf( U[] original, int newLength, Class newType); // public static T[] java.util.Arrays.copyOfRange(U[] original, int from, int to, Class newType); bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { - return false; if (too_many_traps(Deoptimization::Reason_intrinsic)) return false; // Get the arguments. @@ -5369,6 +5376,47 @@ LibraryCallKit::generate_unchecked_arraycopy(const TypePtr* adr_type, src_start, dest_start, copy_length XTOP); } +//-------------inline_encodeISOArray----------------------------------- +// encode char[] to byte[] in ISO_8859_1 +bool LibraryCallKit::inline_encodeISOArray() { + assert(callee()->signature()->size() == 5, "encodeISOArray has 5 parameters"); + // no receiver since it is static method + Node *src = argument(0); + Node *src_offset = argument(1); + Node *dst = argument(2); + Node *dst_offset = argument(3); + Node *length = argument(4); + + const Type* src_type = src->Value(&_gvn); + const Type* dst_type = dst->Value(&_gvn); + const TypeAryPtr* top_src = src_type->isa_aryptr(); + const TypeAryPtr* top_dest = dst_type->isa_aryptr(); + if (top_src == NULL || top_src->klass() == NULL || + top_dest == NULL || top_dest->klass() == NULL) { + // failed array check + return false; + } + + // Figure out the size and type of the elements we will be copying. + BasicType src_elem = src_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + BasicType dst_elem = dst_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + if (src_elem != T_CHAR || dst_elem != T_BYTE) { + return false; + } + Node* src_start = array_element_address(src, src_offset, src_elem); + Node* dst_start = array_element_address(dst, dst_offset, dst_elem); + // 'src_start' points to src array + scaled offset + // 'dst_start' points to dst array + scaled offset + + const TypeAryPtr* mtype = TypeAryPtr::BYTES; + Node* enc = new (C) EncodeISOArrayNode(control(), memory(mtype), src_start, dst_start, length); + enc = _gvn.transform(enc); + Node* res_mem = _gvn.transform(new (C) SCMemProjNode(enc)); + set_memory(res_mem, mtype); + set_result(enc); + return true; +} + //----------------------------inline_reference_get---------------------------- // public T java.lang.ref.Reference.get(); bool LibraryCallKit::inline_reference_get() { diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 259e10a56df..b405bbcf6ba 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -613,6 +613,7 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const { case Op_StrComp: case Op_StrEquals: case Op_StrIndexOf: + case Op_EncodeISOArray: case Op_AryEq: { return false; } @@ -717,6 +718,7 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const { case Op_StrComp: case Op_StrEquals: case Op_StrIndexOf: + case Op_EncodeISOArray: case Op_AryEq: { // Do not unroll a loop with String intrinsics code. // String intrinsics are large and have loops. diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index 30970102d5f..b9b014e050b 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -506,7 +506,7 @@ int MachConstantNode::constant_offset() { #ifndef PRODUCT void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { int reg = ra_->get_reg_first(in(1)->in(_vidx)); - tty->print("%s %s", Name(), Matcher::regName[reg]); + st->print("%s %s", Name(), Matcher::regName[reg]); } #endif diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 2c45140816e..2dde491380c 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -361,14 +361,21 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me } // Otherwise skip it (the call updated 'mem' value). } else if (mem->Opcode() == Op_SCMemProj) { - assert(mem->in(0)->is_LoadStore(), "sanity"); - const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr(); + mem = mem->in(0); + Node* adr = NULL; + if (mem->is_LoadStore()) { + adr = mem->in(MemNode::Address); + } else { + assert(mem->Opcode() == Op_EncodeISOArray, "sanity"); + adr = mem->in(3); // Destination array + } + const TypePtr* atype = adr->bottom_type()->is_ptr(); int adr_idx = Compile::current()->get_alias_index(atype); if (adr_idx == alias_idx) { assert(false, "Object is not scalar replaceable if a LoadStore node access its field"); return NULL; } - mem = mem->in(0)->in(MemNode::Memory); + mem = mem->in(MemNode::Memory); } else { return mem; } @@ -445,7 +452,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type * } values.at_put(j, val); } else if (val->Opcode() == Op_SCMemProj) { - assert(val->in(0)->is_LoadStore(), "sanity"); + assert(val->in(0)->is_LoadStore() || val->in(0)->Opcode() == Op_EncodeISOArray, "sanity"); assert(false, "Object is not scalar replaceable if a LoadStore node access its field"); return NULL; } else { diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 0c6f5ea8ec2..ffd3cc28346 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -919,6 +919,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) { case Op_AryEq: case Op_MemBarVolatile: case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type? + case Op_EncodeISOArray: nidx = Compile::AliasIdxTop; nat = NULL; break; @@ -1982,6 +1983,7 @@ void Matcher::find_shared( Node *n ) { case Op_StrEquals: case Op_StrIndexOf: case Op_AryEq: + case Op_EncodeISOArray: set_shared(n); // Force result into register (it will be anyways) break; case Op_ConP: { // Convert pointers above the centerline to NUL @@ -2183,6 +2185,13 @@ void Matcher::find_shared( Node *n ) { n->del_req(4); break; } + case Op_EncodeISOArray: { + // Restructure into a binary tree for Matching. + Node* pair = new (C) BinaryNode(n->in(3), n->in(4)); + n->set_req(3, pair); + n->del_req(4); + break; + } default: break; } diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index bea81f210da..35fc4b7fc7f 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -2796,6 +2796,26 @@ const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { return bottom_type(); } +//============================================================================= +//------------------------------match_edge------------------------------------- +// Do not match memory edge +uint EncodeISOArrayNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len) +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + +//------------------------------Value------------------------------------------ +const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 92a3d12feba..640eacb116a 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -888,6 +888,22 @@ public: virtual const Type* bottom_type() const { return TypeInt::BOOL; } }; + +//------------------------------EncodeISOArray-------------------------------- +// encode char[] to byte[] in ISO_8859_1 +class EncodeISOArrayNode: public Node { +public: + EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; +}; + //------------------------------MemBar----------------------------------------- // There are different flavors of Memory Barriers to match the Java Memory // Model. Monitor-enter and volatile-load act as Aquires: no following ref diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 9983c84d8e2..16157f68bd7 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -1476,35 +1476,35 @@ static bool is_disconnected(const Node* n) { } #ifdef ASSERT -static void dump_orig(Node* orig) { +static void dump_orig(Node* orig, outputStream *st) { Compile* C = Compile::current(); - if (NotANode(orig)) orig = NULL; - if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL; - if (orig == NULL) return; - tty->print(" !orig="); + if (NotANode(orig)) orig = NULL; + if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL; + if (orig == NULL) return; + st->print(" !orig="); Node* fast = orig->debug_orig(); // tortoise & hare algorithm to detect loops - if (NotANode(fast)) fast = NULL; + if (NotANode(fast)) fast = NULL; while (orig != NULL) { bool discon = is_disconnected(orig); // if discon, print [123] else 123 - if (discon) tty->print("["); + if (discon) st->print("["); if (!Compile::current()->node_arena()->contains(orig)) - tty->print("o"); - tty->print("%d", orig->_idx); - if (discon) tty->print("]"); + st->print("o"); + st->print("%d", orig->_idx); + if (discon) st->print("]"); orig = orig->debug_orig(); - if (NotANode(orig)) orig = NULL; - if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL; - if (orig != NULL) tty->print(","); + if (NotANode(orig)) orig = NULL; + if (orig != NULL && !C->node_arena()->contains(orig)) orig = NULL; + if (orig != NULL) st->print(","); if (fast != NULL) { // Step fast twice for each single step of orig: fast = fast->debug_orig(); - if (NotANode(fast)) fast = NULL; + if (NotANode(fast)) fast = NULL; if (fast != NULL && fast != orig) { fast = fast->debug_orig(); - if (NotANode(fast)) fast = NULL; + if (NotANode(fast)) fast = NULL; } if (fast == orig) { - tty->print("..."); + st->print("..."); break; } } @@ -1531,35 +1531,34 @@ void Node::set_debug_orig(Node* orig) { //------------------------------dump------------------------------------------ // Dump a Node -void Node::dump() const { +void Node::dump(const char* suffix, outputStream *st) const { Compile* C = Compile::current(); bool is_new = C->node_arena()->contains(this); _in_dump_cnt++; - tty->print("%c%d\t%s\t=== ", - is_new ? ' ' : 'o', _idx, Name()); + st->print("%c%d\t%s\t=== ", is_new ? ' ' : 'o', _idx, Name()); // Dump the required and precedence inputs - dump_req(); - dump_prec(); + dump_req(st); + dump_prec(st); // Dump the outputs - dump_out(); + dump_out(st); if (is_disconnected(this)) { #ifdef ASSERT - tty->print(" [%d]",debug_idx()); - dump_orig(debug_orig()); + st->print(" [%d]",debug_idx()); + dump_orig(debug_orig(), st); #endif - tty->cr(); + st->cr(); _in_dump_cnt--; return; // don't process dead nodes } // Dump node-specific info - dump_spec(tty); + dump_spec(st); #ifdef ASSERT // Dump the non-reset _debug_idx - if( Verbose && WizardMode ) { - tty->print(" [%d]",debug_idx()); + if (Verbose && WizardMode) { + st->print(" [%d]",debug_idx()); } #endif @@ -1569,88 +1568,88 @@ void Node::dump() const { const TypeInstPtr *toop = t->isa_instptr(); const TypeKlassPtr *tkls = t->isa_klassptr(); ciKlass* klass = toop ? toop->klass() : (tkls ? tkls->klass() : NULL ); - if( klass && klass->is_loaded() && klass->is_interface() ) { - tty->print(" Interface:"); - } else if( toop ) { - tty->print(" Oop:"); - } else if( tkls ) { - tty->print(" Klass:"); + if (klass && klass->is_loaded() && klass->is_interface()) { + st->print(" Interface:"); + } else if (toop) { + st->print(" Oop:"); + } else if (tkls) { + st->print(" Klass:"); } - t->dump(); - } else if( t == Type::MEMORY ) { - tty->print(" Memory:"); - MemNode::dump_adr_type(this, adr_type(), tty); - } else if( Verbose || WizardMode ) { - tty->print(" Type:"); - if( t ) { - t->dump(); + t->dump_on(st); + } else if (t == Type::MEMORY) { + st->print(" Memory:"); + MemNode::dump_adr_type(this, adr_type(), st); + } else if (Verbose || WizardMode) { + st->print(" Type:"); + if (t) { + t->dump_on(st); } else { - tty->print("no type"); + st->print("no type"); } } else if (t->isa_vect() && this->is_MachSpillCopy()) { // Dump MachSpillcopy vector type. - t->dump(); + t->dump_on(st); } if (is_new) { - debug_only(dump_orig(debug_orig())); + debug_only(dump_orig(debug_orig(), st)); Node_Notes* nn = C->node_notes_at(_idx); if (nn != NULL && !nn->is_clear()) { if (nn->jvms() != NULL) { - tty->print(" !jvms:"); - nn->jvms()->dump_spec(tty); + st->print(" !jvms:"); + nn->jvms()->dump_spec(st); } } } - tty->cr(); + if (suffix) st->print(suffix); _in_dump_cnt--; } //------------------------------dump_req-------------------------------------- -void Node::dump_req() const { +void Node::dump_req(outputStream *st) const { // Dump the required input edges for (uint i = 0; i < req(); i++) { // For all required inputs Node* d = in(i); if (d == NULL) { - tty->print("_ "); + st->print("_ "); } else if (NotANode(d)) { - tty->print("NotANode "); // uninitialized, sentinel, garbage, etc. + st->print("NotANode "); // uninitialized, sentinel, garbage, etc. } else { - tty->print("%c%d ", Compile::current()->node_arena()->contains(d) ? ' ' : 'o', d->_idx); + st->print("%c%d ", Compile::current()->node_arena()->contains(d) ? ' ' : 'o', d->_idx); } } } //------------------------------dump_prec------------------------------------- -void Node::dump_prec() const { +void Node::dump_prec(outputStream *st) const { // Dump the precedence edges int any_prec = 0; for (uint i = req(); i < len(); i++) { // For all precedence inputs Node* p = in(i); if (p != NULL) { - if( !any_prec++ ) tty->print(" |"); - if (NotANode(p)) { tty->print("NotANode "); continue; } - tty->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); + if (!any_prec++) st->print(" |"); + if (NotANode(p)) { st->print("NotANode "); continue; } + st->print("%c%d ", Compile::current()->node_arena()->contains(in(i)) ? ' ' : 'o', in(i)->_idx); } } } //------------------------------dump_out-------------------------------------- -void Node::dump_out() const { +void Node::dump_out(outputStream *st) const { // Delimit the output edges - tty->print(" [["); + st->print(" [["); // Dump the output edges for (uint i = 0; i < _outcnt; i++) { // For all outputs Node* u = _out[i]; if (u == NULL) { - tty->print("_ "); + st->print("_ "); } else if (NotANode(u)) { - tty->print("NotANode "); + st->print("NotANode "); } else { - tty->print("%c%d ", Compile::current()->node_arena()->contains(u) ? ' ' : 'o', u->_idx); + st->print("%c%d ", Compile::current()->node_arena()->contains(u) ? ' ' : 'o', u->_idx); } } - tty->print("]] "); + st->print("]] "); } //------------------------------dump_nodes------------------------------------- diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index f0c1df3a8b0..0dafb00182f 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -994,12 +994,13 @@ public: #ifndef PRODUCT Node* find(int idx) const; // Search the graph for the given idx. Node* find_ctrl(int idx) const; // Search control ancestors for the given idx. - void dump() const; // Print this node, + void dump() const { dump("\n"); } // Print this node. + void dump(const char* suffix, outputStream *st = tty) const;// Print this node. void dump(int depth) const; // Print this node, recursively to depth d void dump_ctrl(int depth) const; // Print control nodes, to depth d - virtual void dump_req() const; // Print required-edge info - virtual void dump_prec() const; // Print precedence-edge info - virtual void dump_out() const; // Print the output edge info + virtual void dump_req(outputStream *st = tty) const; // Print required-edge info + virtual void dump_prec(outputStream *st = tty) const; // Print precedence-edge info + virtual void dump_out(outputStream *st = tty) const; // Print the output edge info virtual void dump_spec(outputStream *st) const {}; // Print per-node info void verify_edges(Unique_Node_List &visited); // Verify bi-directional edges void verify() const; // Check Def-Use info for my subgraph diff --git a/hotspot/src/share/vm/opto/optoreg.hpp b/hotspot/src/share/vm/opto/optoreg.hpp index e6427ea459a..a21311b9c6d 100644 --- a/hotspot/src/share/vm/opto/optoreg.hpp +++ b/hotspot/src/share/vm/opto/optoreg.hpp @@ -77,7 +77,7 @@ class OptoReg VALUE_OBJ_CLASS_SPEC { // (We would like to have an operator+ for RegName, but it is not // a class, so this would be illegal in C++.) - static void dump( int ); + static void dump(int, outputStream *st = tty); // Get the stack slot number of an OptoReg::Name static unsigned int reg2stack( OptoReg::Name r) { diff --git a/hotspot/src/share/vm/opto/regalloc.cpp b/hotspot/src/share/vm/opto/regalloc.cpp index 79dde4066c1..7ac02165662 100644 --- a/hotspot/src/share/vm/opto/regalloc.cpp +++ b/hotspot/src/share/vm/opto/regalloc.cpp @@ -40,6 +40,7 @@ PhaseRegAlloc::PhaseRegAlloc( uint unique, PhaseCFG &cfg, Phase(Register_Allocation), _cfg(cfg), _matcher(matcher), _node_oops(Thread::current()->resource_area()), _node_regs(0), + _node_regs_max_index(0), _framesize(0xdeadbeef) { int i; diff --git a/hotspot/src/share/vm/opto/regmask.cpp b/hotspot/src/share/vm/opto/regmask.cpp index 59413388ca7..f286a873471 100644 --- a/hotspot/src/share/vm/opto/regmask.cpp +++ b/hotspot/src/share/vm/opto/regmask.cpp @@ -108,13 +108,13 @@ int find_hihghest_bit( uint32 mask ) { //------------------------------dump------------------------------------------- #ifndef PRODUCT -void OptoReg::dump( int r ) { - switch( r ) { - case Special: tty->print("r---"); break; - case Bad: tty->print("rBAD"); break; +void OptoReg::dump(int r, outputStream *st) { + switch (r) { + case Special: st->print("r---"); break; + case Bad: st->print("rBAD"); break; default: - if( r < _last_Mach_Reg ) tty->print(Matcher::regName[r]); - else tty->print("rS%d",r); + if (r < _last_Mach_Reg) st->print(Matcher::regName[r]); + else st->print("rS%d",r); break; } } @@ -404,53 +404,53 @@ uint RegMask::Size() const { #ifndef PRODUCT //------------------------------print------------------------------------------ -void RegMask::dump( ) const { - tty->print("["); +void RegMask::dump(outputStream *st) const { + st->print("["); RegMask rm = *this; // Structure copy into local temp OptoReg::Name start = rm.find_first_elem(); // Get a register - if( OptoReg::is_valid(start) ) { // Check for empty mask + if (OptoReg::is_valid(start)) { // Check for empty mask rm.Remove(start); // Yank from mask - OptoReg::dump(start); // Print register + OptoReg::dump(start, st); // Print register OptoReg::Name last = start; // Now I have printed an initial register. // Print adjacent registers as "rX-rZ" instead of "rX,rY,rZ". // Begin looping over the remaining registers. - while( 1 ) { // + while (1) { // OptoReg::Name reg = rm.find_first_elem(); // Get a register - if( !OptoReg::is_valid(reg) ) + if (!OptoReg::is_valid(reg)) break; // Empty mask, end loop rm.Remove(reg); // Yank from mask - if( last+1 == reg ) { // See if they are adjacent + if (last+1 == reg) { // See if they are adjacent // Adjacent registers just collect into long runs, no printing. last = reg; } else { // Ending some kind of run - if( start == last ) { // 1-register run; no special printing - } else if( start+1 == last ) { - tty->print(","); // 2-register run; print as "rX,rY" - OptoReg::dump(last); + if (start == last) { // 1-register run; no special printing + } else if (start+1 == last) { + st->print(","); // 2-register run; print as "rX,rY" + OptoReg::dump(last, st); } else { // Multi-register run; print as "rX-rZ" - tty->print("-"); - OptoReg::dump(last); + st->print("-"); + OptoReg::dump(last, st); } - tty->print(","); // Seperate start of new run + st->print(","); // Seperate start of new run start = last = reg; // Start a new register run - OptoReg::dump(start); // Print register + OptoReg::dump(start, st); // Print register } // End of if ending a register run or not } // End of while regmask not empty - if( start == last ) { // 1-register run; no special printing - } else if( start+1 == last ) { - tty->print(","); // 2-register run; print as "rX,rY" - OptoReg::dump(last); + if (start == last) { // 1-register run; no special printing + } else if (start+1 == last) { + st->print(","); // 2-register run; print as "rX,rY" + OptoReg::dump(last, st); } else { // Multi-register run; print as "rX-rZ" - tty->print("-"); - OptoReg::dump(last); + st->print("-"); + OptoReg::dump(last, st); } - if( rm.is_AllStack() ) tty->print("..."); + if (rm.is_AllStack()) st->print("..."); } - tty->print("]"); + st->print("]"); } #endif diff --git a/hotspot/src/share/vm/opto/regmask.hpp b/hotspot/src/share/vm/opto/regmask.hpp index e4c31dcefb2..7e3376b38a3 100644 --- a/hotspot/src/share/vm/opto/regmask.hpp +++ b/hotspot/src/share/vm/opto/regmask.hpp @@ -310,7 +310,7 @@ public: #ifndef PRODUCT void print() const { dump(); } - void dump() const; // Print a mask + void dump(outputStream *st = tty) const; // Print a mask #endif static const RegMask Empty; // Common empty mask diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 1a8ee2597dd..3928c23aff3 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -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 @@ -1542,10 +1542,10 @@ bool TypeLong::is_finite() const { static const char* longnamenear(jlong x, const char* xname, char* buf, jlong n) { if (n > x) { if (n >= x + 10000) return NULL; - sprintf(buf, "%s+" INT64_FORMAT, xname, n - x); + sprintf(buf, "%s+" JLONG_FORMAT, xname, n - x); } else if (n < x) { if (n <= x - 10000) return NULL; - sprintf(buf, "%s-" INT64_FORMAT, xname, x - n); + sprintf(buf, "%s-" JLONG_FORMAT, xname, x - n); } else { return xname; } @@ -1557,11 +1557,11 @@ static const char* longname(char* buf, jlong n) { if (n == min_jlong) return "min"; else if (n < min_jlong + 10000) - sprintf(buf, "min+" INT64_FORMAT, n - min_jlong); + sprintf(buf, "min+" JLONG_FORMAT, n - min_jlong); else if (n == max_jlong) return "max"; else if (n > max_jlong - 10000) - sprintf(buf, "max-" INT64_FORMAT, max_jlong - n); + sprintf(buf, "max-" JLONG_FORMAT, max_jlong - n); else if ((str = longnamenear(max_juint, "maxuint", buf, n)) != NULL) return str; else if ((str = longnamenear(max_jint, "maxint", buf, n)) != NULL) @@ -1569,7 +1569,7 @@ static const char* longname(char* buf, jlong n) { else if ((str = longnamenear(min_jint, "minint", buf, n)) != NULL) return str; else - sprintf(buf, INT64_FORMAT, n); + sprintf(buf, JLONG_FORMAT, n); return buf; } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index f899aac02e7..f5d126368ff 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -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 @@ -484,15 +484,6 @@ JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) JVM_END -JVM_ENTRY(void, JVM_PrintStackTrace(JNIEnv *env, jobject receiver, jobject printable)) - JVMWrapper("JVM_PrintStackTrace"); - // Note: This is no longer used in Merlin, but we still support it for compatibility. - oop exception = JNIHandles::resolve_non_null(receiver); - oop stream = JNIHandles::resolve_non_null(printable); - java_lang_Throwable::print_stack_trace(exception, stream); -JVM_END - - JVM_ENTRY(jint, JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable)) JVMWrapper("JVM_GetStackTraceDepth"); oop exception = JNIHandles::resolve(throwable); @@ -1582,13 +1573,22 @@ JVM_ENTRY(jbyteArray, JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls)) if (!java_lang_Class::is_primitive(JNIHandles::resolve(cls))) { Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls)); if (k->oop_is_instance()) { - typeArrayOop a = Annotations::make_java_array(InstanceKlass::cast(k)->type_annotations()->class_annotations(), CHECK_NULL); - return (jbyteArray) JNIHandles::make_local(env, a); + Annotations* type_annotations = InstanceKlass::cast(k)->type_annotations(); + if (type_annotations != NULL) { + typeArrayOop a = Annotations::make_java_array(type_annotations->class_annotations(), CHECK_NULL); + return (jbyteArray) JNIHandles::make_local(env, a); + } } } return NULL; JVM_END +static void bounds_check(constantPoolHandle cp, jint index, TRAPS) { + if (!cp->is_within_bounds(index)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool index out of bounds"); + } +} + JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method)) { JVMWrapper("JVM_GetMethodParameters"); @@ -1598,15 +1598,31 @@ JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method)) Handle reflected_method (THREAD, JNIHandles::resolve_non_null(method)); const int num_params = mh->method_parameters_length(); - if(0 != num_params) { + if (0 != num_params) { + // make sure all the symbols are properly formatted + for (int i = 0; i < num_params; i++) { + MethodParametersElement* params = mh->method_parameters_start(); + int index = params[i].name_cp_index; + bounds_check(mh->constants(), index, CHECK_NULL); + + if (0 != index && !mh->constants()->tag_at(index).is_utf8()) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + "Wrong type at constant pool index"); + } + + } + objArrayOop result_oop = oopFactory::new_objArray(SystemDictionary::reflect_Parameter_klass(), num_params, CHECK_NULL); objArrayHandle result (THREAD, result_oop); - for(int i = 0; i < num_params; i++) { + for (int i = 0; i < num_params; i++) { MethodParametersElement* params = mh->method_parameters_start(); - Symbol* const sym = mh->constants()->symbol_at(params[i].name_cp_index); + // For a 0 index, give a NULL symbol + Symbol* const sym = 0 != params[i].name_cp_index ? + mh->constants()->symbol_at(params[i].name_cp_index) : NULL; + int flags = build_int_from_shorts(params[i].flags_lo, params[i].flags_hi); oop param = Reflection::new_parameter(reflected_method, i, sym, - params[i].flags, CHECK_NULL); + flags, CHECK_NULL); result->obj_at_put(i, param); } return (jobjectArray)JNIHandles::make_local(env, result()); @@ -1830,13 +1846,6 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused JVM_END -static void bounds_check(constantPoolHandle cp, jint index, TRAPS) { - if (!cp->is_within_bounds(index)) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool index out of bounds"); - } -} - - JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetClassAt"); @@ -1851,7 +1860,6 @@ JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject u } JVM_END - JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) { JVMWrapper("JVM_ConstantPoolGetClassAtIfLoaded"); diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 899138ede9e..c081f872afa 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -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 @@ -212,9 +212,6 @@ JVM_IsNaN(jdouble d); JNIEXPORT void JNICALL JVM_FillInStackTrace(JNIEnv *env, jobject throwable); -JNIEXPORT void JNICALL -JVM_PrintStackTrace(JNIEnv *env, jobject throwable, jobject printable); - JNIEXPORT jint JNICALL JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index a9d3d5f1e39..7e68f2b1059 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -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 @@ -1334,20 +1334,8 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( return JVMTI_ERROR_INTERNAL; } - int orig_length = old_cp->orig_length(); - if (orig_length == 0) { - // This old_cp is an actual original constant pool. We save - // the original length in the merged constant pool so that - // merge_constant_pools() can be more efficient. If a constant - // pool has a non-zero orig_length() value, then that constant - // pool was created by a merge operation in RedefineClasses. - merge_cp->set_orig_length(old_cp->length()); - } else { - // This old_cp is a merged constant pool from a previous - // RedefineClasses() calls so just copy the orig_length() - // value. - merge_cp->set_orig_length(old_cp->orig_length()); - } + // Update the version number of the constant pool + merge_cp->increment_and_save_version(old_cp->version()); ResourceMark rm(THREAD); _index_map_count = 0; @@ -2417,18 +2405,19 @@ void VM_RedefineClasses::set_new_constant_pool( int scratch_cp_length, TRAPS) { assert(scratch_cp->length() >= scratch_cp_length, "sanity check"); - // scratch_cp is a merged constant pool and has enough space for a - // worst case merge situation. We want to associate the minimum - // sized constant pool with the klass to save space. - constantPoolHandle smaller_cp(THREAD, - ConstantPool::allocate(loader_data, scratch_cp_length, - THREAD)); - // preserve orig_length() value in the smaller copy - int orig_length = scratch_cp->orig_length(); - assert(orig_length != 0, "sanity check"); - smaller_cp->set_orig_length(orig_length); - scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD); - scratch_cp = smaller_cp; + // scratch_cp is a merged constant pool and has enough space for a + // worst case merge situation. We want to associate the minimum + // sized constant pool with the klass to save space. + constantPoolHandle smaller_cp(THREAD, + ConstantPool::allocate(loader_data, scratch_cp_length, THREAD)); + + // preserve version() value in the smaller copy + int version = scratch_cp->version(); + assert(version != 0, "sanity check"); + smaller_cp->set_version(version); + + scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD); + scratch_cp = smaller_cp; // attach new constant pool to klass scratch_cp->set_pool_holder(scratch_class()); diff --git a/hotspot/src/share/vm/runtime/aprofiler.cpp b/hotspot/src/share/vm/runtime/aprofiler.cpp index 6c4e9cc428d..e71bfb587ef 100644 --- a/hotspot/src/share/vm/runtime/aprofiler.cpp +++ b/hotspot/src/share/vm/runtime/aprofiler.cpp @@ -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 @@ -129,7 +129,7 @@ void AllocationProfiler::print(size_t cutoff) { assert(!is_active(), "AllocationProfiler cannot be active while printing profile"); tty->cr(); - tty->print_cr("Allocation profile (sizes in bytes, cutoff = %ld bytes):", cutoff * BytesPerWord); + tty->print_cr("Allocation profile (sizes in bytes, cutoff = " SIZE_FORMAT " bytes):", cutoff * BytesPerWord); tty->cr(); // Print regular instance klasses and basic type array klasses diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 5978382e9fe..9b5d7f9122d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -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 @@ -532,7 +532,7 @@ char* SysClassPath::add_jars_to_path(char* path, const char* directory) { // Parses a memory size specification string. static bool atomull(const char *s, julong* result) { julong n = 0; - int args_read = sscanf(s, os::julong_format_specifier(), &n); + int args_read = sscanf(s, JULONG_FORMAT, &n); if (args_read != 1) { return false; } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 7ea96627e82..7db81d805bd 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -929,11 +929,14 @@ class CommandLineFlags { "Starts debugger when an implicit OS (e.g., NULL) " \ "exception happens") \ \ - notproduct(bool, PrintCodeCache, false, \ - "Print the compiled_code cache when exiting") \ + product(bool, PrintCodeCache, false, \ + "Print the code cache memory usage when exiting") \ \ develop(bool, PrintCodeCache2, false, \ - "Print detailed info on the compiled_code cache when exiting") \ + "Print detailed usage info on the code cache when exiting") \ + \ + product(bool, PrintCodeCacheOnCompilation, false, \ + "Print the code cache memory usage each time a method is compiled") \ \ diagnostic(bool, PrintStubCode, false, \ "Print generated stub code") \ @@ -969,18 +972,6 @@ class CommandLineFlags { notproduct(uintx, WarnOnStalledSpinLock, 0, \ "Prints warnings for stalled SpinLocks") \ \ - develop(bool, InitializeJavaLangSystem, true, \ - "Initialize java.lang.System - turn off for individual " \ - "method debugging") \ - \ - develop(bool, InitializeJavaLangString, true, \ - "Initialize java.lang.String - turn off for individual " \ - "method debugging") \ - \ - develop(bool, InitializeJavaLangExceptionsErrors, true, \ - "Initialize various error and exception classes - turn off for " \ - "individual method debugging") \ - \ product(bool, RegisterFinalizersAtInit, true, \ "Register finalizable objects at end of Object. or " \ "after allocation") \ @@ -1075,7 +1066,7 @@ class CommandLineFlags { \ product(intx, ClearFPUAtPark, 0, "(Unsafe,Unstable)" ) \ \ - product(intx, hashCode, 0, \ + product(intx, hashCode, 5, \ "(Unstable) select hashCode generation algorithm" ) \ \ product(intx, WorkAroundNPTLTimedWaitHang, 1, \ @@ -1166,6 +1157,18 @@ class CommandLineFlags { notproduct(bool, PrintCompactFieldsSavings, false, \ "Print how many words were saved with CompactFields") \ \ + notproduct(bool, PrintFieldLayout, false, \ + "Print field layout for each class") \ + \ + product(intx, ContendedPaddingWidth, 128, \ + "How many bytes to pad the fields/classes marked @Contended with")\ + \ + product(bool, EnableContended, true, \ + "Enable @Contended annotation support") \ + \ + product(bool, RestrictContended, true, \ + "Restrict @Contended to trusted classes") \ + \ product(bool, UseBiasedLocking, true, \ "Enable biased locking in JVM") \ \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index ad6399495b0..fd9050d9cb1 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -368,6 +368,12 @@ void print_statistics() { if (CITime) { CompileBroker::print_times(); } + + if (PrintCodeCache) { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print(); + } + #ifdef COMPILER2 if (PrintPreciseBiasedLockingStatistics) { OptoRuntime::print_named_counters(); @@ -542,6 +548,10 @@ void before_exit(JavaThread * thread) { BeforeExit_lock->notify_all(); } + // Shutdown NMT before exit. Otherwise, + // it will run into trouble when system destroys static variables. + MemTracker::shutdown(MemTracker::NMT_normal); + #undef BEFORE_EXIT_NOT_RUN #undef BEFORE_EXIT_RUNNING #undef BEFORE_EXIT_DONE diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp index 2eefe291112..d6d2f1c3173 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -653,8 +653,7 @@ void ATTR ObjectMonitor::EnterI (TRAPS) { assert (_succ != Self, "invariant") ; if (_Responsible == Self) { _Responsible = NULL ; - // Dekker pivot-point. - // Consider OrderAccess::storeload() here + OrderAccess::fence(); // Dekker pivot-point // We may leave threads on cxq|EntryList without a designated // "Responsible" thread. This is benign. When this thread subsequently @@ -674,10 +673,6 @@ void ATTR ObjectMonitor::EnterI (TRAPS) { // // The MEMBAR, above, prevents the LD of cxq|EntryList in the subsequent // exit operation from floating above the ST Responsible=null. - // - // In *practice* however, EnterI() is always followed by some atomic - // operation such as the decrement of _count in ::enter(). Those atomics - // obviate the need for the explicit MEMBAR, above. } // We've acquired ownership with CAS(). diff --git a/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp b/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp index 2107523a3e8..ebe2b7dcbe2 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, 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 @@ -101,10 +101,12 @@ inline intptr_t ObjectMonitor::contentions() const { return _count; } +// Do NOT set _count = 0. There is a race such that _count could +// be set while inflating prior to setting _owner +// Just use Atomic::inc/dec and assert 0 when monitor put on free list inline void ObjectMonitor::set_owner(void* owner) { _owner = owner; _recursions = 0; - _count = 0; } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 235005f9890..d061a0848c6 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -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 @@ -641,10 +641,6 @@ class os: AllStatic { static struct hostent* get_host_by_name(char* name); - // Printing 64 bit integers - static const char* jlong_format_specifier(); - static const char* julong_format_specifier(); - // Support for signals (see JVM_RaiseSignal, JVM_RegisterSignal) static void signal_init(); static void signal_init_pd(); diff --git a/hotspot/src/share/vm/runtime/perfData.cpp b/hotspot/src/share/vm/runtime/perfData.cpp index ddb565b074c..777ea27f906 100644 --- a/hotspot/src/share/vm/runtime/perfData.cpp +++ b/hotspot/src/share/vm/runtime/perfData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -192,7 +192,7 @@ PerfLong::PerfLong(CounterNS ns, const char* namep, Units u, Variability v) } int PerfLong::format(char* buffer, int length) { - return jio_snprintf(buffer, length,"%lld", *(jlong*)_valuep); + return jio_snprintf(buffer, length, JLONG_FORMAT, *(jlong*)_valuep); } PerfLongVariant::PerfLongVariant(CounterNS ns, const char* namep, Units u, diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index 76a72e4e9b7..8d0cab2a441 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -862,7 +862,15 @@ oop Reflection::new_field(fieldDescriptor* fd, bool intern_name, TRAPS) { oop Reflection::new_parameter(Handle method, int index, Symbol* sym, int flags, TRAPS) { - Handle name = java_lang_String::create_from_symbol(sym, CHECK_NULL); + Handle name; + + // A null symbol here translates to the empty string + if(NULL != sym) { + name = java_lang_String::create_from_symbol(sym, CHECK_NULL); + } else { + name = java_lang_String::create_from_str("", CHECK_NULL); + } + Handle rh = java_lang_reflect_Parameter::create(CHECK_NULL); java_lang_reflect_Parameter::set_name(rh(), name()); java_lang_reflect_Parameter::set_modifiers(rh(), flags); diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index 13b71cb806f..667066e7f17 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -333,7 +333,9 @@ bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) { void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { TEVENT (jni_exit) ; if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + Handle h_obj(THREAD, obj); + BiasedLocking::revoke_and_rebias(h_obj, false, THREAD); + obj = h_obj(); } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index db3cace3d64..ff6adde6eee 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1716,7 +1716,6 @@ static void ensure_join(JavaThread* thread) { // cleanup_failed_attach_current_thread as well. void JavaThread::exit(bool destroy_vm, ExitType exit_type) { assert(this == JavaThread::current(), "thread consistency check"); - if (!InitializeJavaLangSystem) return; HandleMark hm(this); Handle uncaught_exception(this, this->pending_exception()); @@ -3469,11 +3468,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { create_vm_init_libraries(); } - if (InitializeJavaLangString) { - initialize_class(vmSymbols::java_lang_String(), CHECK_0); - } else { - warning("java.lang.String not initialized"); - } + initialize_class(vmSymbols::java_lang_String(), CHECK_0); if (AggressiveOpts) { { @@ -3514,53 +3509,39 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { } // Initialize java_lang.System (needed before creating the thread) - if (InitializeJavaLangSystem) { - initialize_class(vmSymbols::java_lang_System(), CHECK_0); - initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0); - Handle thread_group = create_initial_thread_group(CHECK_0); - Universe::set_main_thread_group(thread_group()); - initialize_class(vmSymbols::java_lang_Thread(), CHECK_0); - oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0); - main_thread->set_threadObj(thread_object); - // Set thread status to running since main thread has - // been started and running. - java_lang_Thread::set_thread_status(thread_object, - java_lang_Thread::RUNNABLE); + initialize_class(vmSymbols::java_lang_System(), CHECK_0); + initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0); + Handle thread_group = create_initial_thread_group(CHECK_0); + Universe::set_main_thread_group(thread_group()); + initialize_class(vmSymbols::java_lang_Thread(), CHECK_0); + oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0); + main_thread->set_threadObj(thread_object); + // Set thread status to running since main thread has + // been started and running. + java_lang_Thread::set_thread_status(thread_object, + java_lang_Thread::RUNNABLE); - // The VM creates & returns objects of this class. Make sure it's initialized. - initialize_class(vmSymbols::java_lang_Class(), CHECK_0); + // The VM creates & returns objects of this class. Make sure it's initialized. + initialize_class(vmSymbols::java_lang_Class(), CHECK_0); - // The VM preresolves methods to these classes. Make sure that they get initialized - initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0); - initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK_0); - call_initializeSystemClass(CHECK_0); + // The VM preresolves methods to these classes. Make sure that they get initialized + initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0); + initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK_0); + call_initializeSystemClass(CHECK_0); - // get the Java runtime name after java.lang.System is initialized - JDK_Version::set_runtime_name(get_java_runtime_name(THREAD)); - JDK_Version::set_runtime_version(get_java_runtime_version(THREAD)); - } else { - warning("java.lang.System not initialized"); - } + // get the Java runtime name after java.lang.System is initialized + JDK_Version::set_runtime_name(get_java_runtime_name(THREAD)); + JDK_Version::set_runtime_version(get_java_runtime_version(THREAD)); // an instance of OutOfMemory exception has been allocated earlier - if (InitializeJavaLangExceptionsErrors) { - initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0); - initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0); - initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0); - initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0); - initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0); - initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0); - initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0); - initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); - } else { - warning("java.lang.OutOfMemoryError has not been initialized"); - warning("java.lang.NullPointerException has not been initialized"); - warning("java.lang.ClassCastException has not been initialized"); - warning("java.lang.ArrayStoreException has not been initialized"); - warning("java.lang.ArithmeticException has not been initialized"); - warning("java.lang.StackOverflowError has not been initialized"); - warning("java.lang.IllegalArgumentException has not been initialized"); - } + initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0); + initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0); + initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0); + initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0); + initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0); + initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0); + initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0); + initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); } // See : bugid 4211085. @@ -4011,10 +3992,6 @@ bool Threads::destroy_vm() { Mutex::_as_suspend_equivalent_flag); } - // Shutdown NMT before exit. Otherwise, - // it will run into trouble when system destroys static variables. - MemTracker::shutdown(MemTracker::NMT_normal); - // Hang forever on exit if we are reporting an error. if (ShowMessageBoxOnError && is_error_reported()) { os::infinite_sleep(); diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index f33c1995e34..dffb588dbae 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -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 @@ -868,8 +868,8 @@ void VirtualSpace::print() { tty->print ("Virtual space:"); if (special()) tty->print(" (pinned in memory)"); tty->cr(); - tty->print_cr(" - committed: %ld", committed_size()); - tty->print_cr(" - reserved: %ld", reserved_size()); + tty->print_cr(" - committed: " SIZE_FORMAT, committed_size()); + tty->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); tty->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low(), high()); tty->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 9ac10e26d4c..a1fe3f2aa63 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -257,8 +257,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; c1_nonstatic_field, \ c2_nonstatic_field, \ unchecked_c1_static_field, \ - unchecked_c2_static_field, \ - last_entry) \ + unchecked_c2_static_field) \ \ /******************************************************************/ \ /* OopDesc and Klass hierarchies (NOTE: MethodData* incomplete) */ \ @@ -718,7 +717,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(ClassLoaderData, _next, ClassLoaderData*) \ \ static_field(ClassLoaderDataGraph, _head, ClassLoaderData*) \ - nonstatic_field(ClassLoaderDataGraph, _unloading, ClassLoaderData*) \ \ /*******************/ \ /* GrowableArrays */ \ @@ -1200,7 +1198,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; /*********************************/ \ \ static_field(java_lang_Class, _klass_offset, int) \ - static_field(java_lang_Class, _resolved_constructor_offset, int) \ static_field(java_lang_Class, _array_klass_offset, int) \ static_field(java_lang_Class, _oop_size_offset, int) \ static_field(java_lang_Class, _static_oop_field_count_offset, int) \ @@ -1238,9 +1235,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(FreeList, _count, ssize_t) \ nonstatic_field(MetablockTreeDictionary, _total_size, size_t) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */ - /* be present there) */ //-------------------------------------------------------------------------------- // VM_TYPES @@ -1280,8 +1274,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_unsigned_integer_type, \ declare_c1_toplevel_type, \ declare_c2_type, \ - declare_c2_toplevel_type, \ - last_entry) \ + declare_c2_toplevel_type) \ \ /*************************************************************/ \ /* Java primitive types -- required by the SA implementation */ \ @@ -2098,10 +2091,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_type(MetablockTreeDictionary, FreeBlockDictionary) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must be */ - /* present there) */ - //-------------------------------------------------------------------------------- // VM_INT_CONSTANTS // @@ -2114,8 +2103,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_preprocessor_constant, \ declare_c1_constant, \ declare_c2_constant, \ - declare_c2_preprocessor_constant, \ - last_entry) \ + declare_c2_preprocessor_constant) \ \ /******************/ \ /* Useful globals */ \ @@ -2294,10 +2282,18 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_constant(FieldInfo::name_index_offset) \ declare_constant(FieldInfo::signature_index_offset) \ declare_constant(FieldInfo::initval_index_offset) \ - declare_constant(FieldInfo::low_offset) \ - declare_constant(FieldInfo::high_offset) \ + declare_constant(FieldInfo::low_packed_offset) \ + declare_constant(FieldInfo::high_packed_offset) \ declare_constant(FieldInfo::field_slots) \ \ + /*************************************/ \ + /* FieldInfo tag constants */ \ + /*************************************/ \ + \ + declare_preprocessor_constant("FIELDINFO_TAG_SIZE", FIELDINFO_TAG_SIZE) \ + declare_preprocessor_constant("FIELDINFO_TAG_MASK", FIELDINFO_TAG_MASK) \ + declare_preprocessor_constant("FIELDINFO_TAG_OFFSET", FIELDINFO_TAG_OFFSET) \ + \ /************************************************/ \ /* InstanceKlass InnerClassAttributeOffset enum */ \ /************************************************/ \ @@ -2483,9 +2479,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_c2_preprocessor_constant("SAVED_ON_ENTRY_REG_COUNT", SAVED_ON_ENTRY_REG_COUNT) \ declare_c2_preprocessor_constant("C_SAVED_ON_ENTRY_REG_COUNT", C_SAVED_ON_ENTRY_REG_COUNT) - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and */ - /* must be present there) */ //-------------------------------------------------------------------------------- // VM_LONG_CONSTANTS @@ -2495,7 +2488,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; // enums, etc., while "declare_preprocessor_constant" must be used for // all #defined constants. -#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \ +#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ \ /*********************/ \ /* MarkOop constants */ \ @@ -2541,11 +2534,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; /* Constants in markOop used by CMS. */ \ declare_constant(markOopDesc::cms_shift) \ declare_constant(markOopDesc::cms_mask) \ - declare_constant(markOopDesc::size_shift) \ - - /* NOTE that we do not use the last_entry() macro here; it is used */ - /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and */ - /* must be present there) */ + declare_constant(markOopDesc::size_shift) //-------------------------------------------------------------------------------- @@ -2585,7 +2574,8 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; // This macro checks the type of a VMStructEntry by comparing pointer types #define CHECK_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; } + {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; \ + assert(offset_of(typeName, fieldName) < sizeof(typeName), "Illegal nonstatic struct entry, field offset too large"); } // This macro checks the type of a volatile VMStructEntry by comparing pointer types #define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ @@ -2608,9 +2598,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; // This is a no-op macro for unchecked fields #define CHECK_NO_OP(a, b, c) -// This is a no-op macro for the sentinel value -#define CHECK_SENTINEL() - // // Build-specific macros: // @@ -2789,48 +2776,47 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; // as long as class VMStructs is a friend VMStructEntry VMStructs::localHotSpotVMStructs[] = { - VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C1_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_VM_STRUCT_LAST_ENTRY) + VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) #ifndef SERIALGC - VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ + VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) - VM_STRUCTS_CMS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ + VM_STRUCTS_CMS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) - VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ + VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) #endif // SERIALGC - VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_VM_STRUCT_LAST_ENTRY) + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) - VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, \ - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY, \ - GENERATE_VM_STRUCT_LAST_ENTRY) + VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + + GENERATE_VM_STRUCT_LAST_ENTRY() }; VMTypeEntry VMStructs::localHotSpotVMTypes[] = { @@ -2842,8 +2828,7 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_VM_TYPE_LAST_ENTRY) + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) #ifndef SERIALGC VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, @@ -2865,8 +2850,7 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_VM_TYPE_LAST_ENTRY) + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, @@ -2875,8 +2859,9 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_VM_TYPE_LAST_ENTRY) + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + + GENERATE_VM_TYPE_LAST_ENTRY() }; VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { @@ -2885,8 +2870,7 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_VM_INT_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #ifndef SERIALGC VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -2898,15 +2882,15 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_VM_INT_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_OS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_VM_INT_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + + GENERATE_VM_INT_CONSTANT_LAST_ENTRY() }; VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { @@ -2915,22 +2899,21 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_VM_LONG_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_VM_LONG_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_OS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_VM_LONG_CONSTANT_LAST_ENTRY) + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; // This is used both to check the types of referenced fields and, in @@ -2945,8 +2928,7 @@ VMStructs::init() { CHECK_C1_NONSTATIC_VM_STRUCT_ENTRY, CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, - CHECK_NO_OP, - CHECK_SENTINEL); + CHECK_NO_OP); #ifndef SERIALGC VM_STRUCTS_PARALLELGC(CHECK_NONSTATIC_VM_STRUCT_ENTRY, @@ -2967,8 +2949,7 @@ VMStructs::init() { CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, - CHECK_NO_OP, - CHECK_SENTINEL); + CHECK_NO_OP); VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, @@ -2977,8 +2958,7 @@ VMStructs::init() { CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, - CHECK_NO_OP, - CHECK_SENTINEL); + CHECK_NO_OP); VM_TYPES(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -2987,8 +2967,7 @@ VMStructs::init() { CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_SENTINEL); + CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); #ifndef SERIALGC VM_TYPES_PARALLELGC(CHECK_VM_TYPE_ENTRY, @@ -3010,8 +2989,7 @@ VMStructs::init() { CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_SENTINEL); + CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -3020,8 +2998,7 @@ VMStructs::init() { CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_SENTINEL); + CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); // // Split VM_STRUCTS() invocation into two parts to allow MS VC++ 6.0 @@ -3040,53 +3017,49 @@ VMStructs::init() { // Solstice NFS setup. If everyone switches to local workspaces on // Win32, we can put this back in. #ifndef _WINDOWS - debug_only(VM_STRUCTS(ENSURE_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_SENTINEL)); - debug_only(VM_STRUCTS(CHECK_NO_OP, \ - ENSURE_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, \ - ENSURE_C1_FIELD_TYPE_PRESENT, \ - ENSURE_C2_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_SENTINEL)); + debug_only(VM_STRUCTS(ENSURE_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP, + CHECK_NO_OP)); + debug_only(VM_STRUCTS(CHECK_NO_OP, + ENSURE_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + ENSURE_FIELD_TYPE_PRESENT, + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, + ENSURE_C1_FIELD_TYPE_PRESENT, + ENSURE_C2_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + CHECK_NO_OP)); #ifndef SERIALGC - debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, \ + debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); - debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_FIELD_TYPE_PRESENT, \ + debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, + ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); - debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT, \ + debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); #endif // SERIALGC - debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, \ - ENSURE_C2_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_SENTINEL)); - debug_only(VM_STRUCTS_OS_CPU(ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - ENSURE_FIELD_TYPE_PRESENT, \ - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, \ - ENSURE_C2_FIELD_TYPE_PRESENT, \ - CHECK_NO_OP, \ - CHECK_NO_OP, \ - CHECK_SENTINEL)); + debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, + ENSURE_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + ENSURE_FIELD_TYPE_PRESENT, + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, + ENSURE_C2_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + CHECK_NO_OP)); + debug_only(VM_STRUCTS_OS_CPU(ENSURE_FIELD_TYPE_PRESENT, + ENSURE_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + ENSURE_FIELD_TYPE_PRESENT, + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, + ENSURE_C2_FIELD_TYPE_PRESENT, + CHECK_NO_OP, + CHECK_NO_OP)); #endif } @@ -3146,10 +3119,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - delete s; + delete [] s; return 1; } - delete s; + delete [] s; } const char* start = NULL; if (strstr(typeName, "GrowableArray<") == typeName) { @@ -3165,10 +3138,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - delete s; + delete [] s; return 1; } - delete s; + delete [] s; } if (strstr(typeName, "const ") == typeName) { const char * s = typeName + strlen("const "); @@ -3182,8 +3155,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len - 6] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { + free(s); return 1; } + free(s); } if (!isRecurse) { tty->print_cr("type \"%s\" not found", typeName); @@ -3206,6 +3181,30 @@ void vmStructs_init() { #ifndef PRODUCT void VMStructs::test() { + // Make sure last entry in the each array is indeed the correct end marker. + // The reason why these are static is to make sure they are zero initialized. + // Putting them on the stack will leave some garbage in the padding of some fields. + static VMStructEntry struct_last_entry = GENERATE_VM_STRUCT_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMStructs[(sizeof(localHotSpotVMStructs) / sizeof(VMStructEntry)) - 1], + &struct_last_entry, + sizeof(VMStructEntry)) == 0, "Incorrect last entry in localHotSpotVMStructs"); + + static VMTypeEntry type_last_entry = GENERATE_VM_TYPE_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMTypes[sizeof(localHotSpotVMTypes) / sizeof(VMTypeEntry) - 1], + &type_last_entry, + sizeof(VMTypeEntry)) == 0, "Incorrect last entry in localHotSpotVMTypes"); + + static VMIntConstantEntry int_last_entry = GENERATE_VM_INT_CONSTANT_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMIntConstants[sizeof(localHotSpotVMIntConstants) / sizeof(VMIntConstantEntry) - 1], + &int_last_entry, + sizeof(VMIntConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMIntConstants"); + + static VMLongConstantEntry long_last_entry = GENERATE_VM_LONG_CONSTANT_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMLongConstants[sizeof(localHotSpotVMLongConstants) / sizeof(VMLongConstantEntry) - 1], + &long_last_entry, + sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); + + // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { for (int j = i + 1; localHotSpotVMTypes[j].typeName != NULL; j++) { diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index d8d3e444780..286d457c997 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -570,7 +570,11 @@ void VMThread::execute(VM_Operation* op) { if (!t->is_VM_thread()) { SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot // JavaThread or WatcherThread - t->check_for_valid_safepoint_state(true); + bool concurrent = op->evaluate_concurrently(); + // only blocking VM operations need to verify the caller's safepoint state: + if (!concurrent) { + t->check_for_valid_safepoint_state(true); + } // New request from Java thread, evaluate prologue if (!op->doit_prologue()) { @@ -582,7 +586,6 @@ void VMThread::execute(VM_Operation* op) { // It does not make sense to execute the epilogue, if the VM operation object is getting // deallocated by the VM thread. - bool concurrent = op->evaluate_concurrently(); bool execute_epilog = !op->is_cheap_allocated(); assert(!concurrent || op->is_cheap_allocated(), "concurrent => cheap_allocated"); diff --git a/hotspot/src/share/vm/services/diagnosticArgument.cpp b/hotspot/src/share/vm/services/diagnosticArgument.cpp index 826b530bcb2..5d0eb756b28 100644 --- a/hotspot/src/share/vm/services/diagnosticArgument.cpp +++ b/hotspot/src/share/vm/services/diagnosticArgument.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -86,7 +86,7 @@ void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) { template <> void DCmdArgument::parse_value(const char* str, size_t len, TRAPS) { - if (str == NULL || sscanf(str, INT64_FORMAT, &_value) != 1) { + if (str == NULL || sscanf(str, JLONG_FORMAT, &_value) != 1) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Integer parsing error in diagnostic command arguments\n"); } @@ -171,7 +171,7 @@ template <> void DCmdArgument::parse_value(const char* str, "Integer parsing error nanotime value: syntax error"); } - int argc = sscanf(str, INT64_FORMAT , &_value._time); + int argc = sscanf(str, JLONG_FORMAT, &_value._time); if (argc != 1) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Integer parsing error nanotime value: syntax error"); diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 0dbe2e86589..65ee27f457a 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -1866,7 +1866,7 @@ int HeapDumper::dump(const char* path) { if (error() == NULL) { char msg[256]; sprintf(msg, "Heap dump file created [%s bytes in %3.3f secs]", - os::jlong_format_specifier(), timer()->seconds()); + JLONG_FORMAT, timer()->seconds()); tty->print_cr(msg, writer.bytes_written()); } else { tty->print_cr("Dump file is incomplete: %s", writer.error()); diff --git a/hotspot/src/share/vm/services/lowMemoryDetector.cpp b/hotspot/src/share/vm/services/lowMemoryDetector.cpp index babd93ac85b..199a342dd77 100644 --- a/hotspot/src/share/vm/services/lowMemoryDetector.cpp +++ b/hotspot/src/share/vm/services/lowMemoryDetector.cpp @@ -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 @@ -353,7 +353,7 @@ void SensorInfo::clear(int count, TRAPS) { #ifndef PRODUCT void SensorInfo::print() { - tty->print_cr("%s count = %ld pending_triggers = %ld pending_clears = %ld", + tty->print_cr("%s count = " SIZE_FORMAT " pending_triggers = %ld pending_clears = %ld", (_sensor_on ? "on" : "off"), _sensor_count, _pending_trigger_count, _pending_clear_count); } diff --git a/hotspot/src/share/vm/shark/sharkBlock.cpp b/hotspot/src/share/vm/shark/sharkBlock.cpp index b4e98365efc..6b1b5fbe89c 100644 --- a/hotspot/src/share/vm/shark/sharkBlock.cpp +++ b/hotspot/src/share/vm/shark/sharkBlock.cpp @@ -1032,7 +1032,7 @@ void SharkBlock::do_field_access(bool is_get, bool is_field) { check_null(value); object = value->generic_value(); } - if (is_get && field->is_constant()) { + if (is_get && field->is_constant() && field->is_static()) { SharkConstant *constant = SharkConstant::for_field(iter()); if (constant->is_loaded()) value = constant->value(builder()); @@ -1044,10 +1044,17 @@ void SharkBlock::do_field_access(bool is_get, bool is_field) { BasicType basic_type = field->type()->basic_type(); Type *stack_type = SharkType::to_stackType(basic_type); Type *field_type = SharkType::to_arrayType(basic_type); - + Type *type = field_type; + if (field->is_volatile()) { + if (field_type == SharkType::jfloat_type()) { + type = SharkType::jint_type(); + } else if (field_type == SharkType::jdouble_type()) { + type = SharkType::jlong_type(); + } + } Value *addr = builder()->CreateAddressOfStructEntry( object, in_ByteSize(field->offset_in_bytes()), - PointerType::getUnqual(field_type), + PointerType::getUnqual(type), "addr"); // Do the access @@ -1055,6 +1062,7 @@ void SharkBlock::do_field_access(bool is_get, bool is_field) { Value* field_value; if (field->is_volatile()) { field_value = builder()->CreateAtomicLoad(addr); + field_value = builder()->CreateBitCast(field_value, field_type); } else { field_value = builder()->CreateLoad(addr); } @@ -1074,6 +1082,7 @@ void SharkBlock::do_field_access(bool is_get, bool is_field) { } if (field->is_volatile()) { + field_value = builder()->CreateBitCast(field_value, type); builder()->CreateAtomicStore(field_value, addr); } else { builder()->CreateStore(field_value, addr); diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp index 3438240ad00..cde6bc23e76 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.cpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp @@ -185,6 +185,9 @@ void SharkCompiler::compile_method(ciEnv* env, // Build the LLVM IR for the method Function *function = SharkFunction::build(env, &builder, flow, name); + if (env->failing()) { + return; + } // Generate native code. It's unpleasant that we have to drop into // the VM to do this -- it blocks safepoints -- but I can't see any diff --git a/hotspot/src/share/vm/shark/sharkCompiler.hpp b/hotspot/src/share/vm/shark/sharkCompiler.hpp index 828a783a80d..7e530c142aa 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.hpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp @@ -46,6 +46,9 @@ class SharkCompiler : public AbstractCompiler { // Missing feature tests bool supports_native() { return true; } bool supports_osr() { return true; } + bool can_compile_method(methodHandle method) { + return ! (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()); + } // Customization bool needs_adapters() { return false; } diff --git a/hotspot/src/share/vm/shark/sharkConstant.cpp b/hotspot/src/share/vm/shark/sharkConstant.cpp index b45ec136e77..cd6e1152d0f 100644 --- a/hotspot/src/share/vm/shark/sharkConstant.cpp +++ b/hotspot/src/share/vm/shark/sharkConstant.cpp @@ -37,7 +37,12 @@ SharkConstant* SharkConstant::for_ldc(ciBytecodeStream *iter) { ciType *type = NULL; if (constant.basic_type() == T_OBJECT) { ciEnv *env = ciEnv::current(); - assert(constant.as_object()->klass() == env->String_klass() || constant.as_object()->klass() == env->Class_klass(), "should be"); + + assert(constant.as_object()->klass() == env->String_klass() + || constant.as_object()->klass() == env->Class_klass() + || constant.as_object()->klass()->is_subtype_of(env->MethodType_klass()) + || constant.as_object()->klass()->is_subtype_of(env->MethodHandle_klass()), "should be"); + type = constant.as_object()->klass(); } return new SharkConstant(constant, type); diff --git a/hotspot/src/share/vm/shark/sharkFunction.cpp b/hotspot/src/share/vm/shark/sharkFunction.cpp index 917ed0109ac..1ec7a371fb4 100644 --- a/hotspot/src/share/vm/shark/sharkFunction.cpp +++ b/hotspot/src/share/vm/shark/sharkFunction.cpp @@ -77,6 +77,10 @@ void SharkFunction::initialize(const char *name) { // Walk the tree from the start block to determine which // blocks are entered and which blocks require phis SharkTopLevelBlock *start_block = block(flow()->start_block_num()); + if (is_osr() && start_block->stack_depth_at_entry() != 0) { + env()->record_method_not_compilable("can't compile OSR block with incoming stack-depth > 0"); + return; + } assert(start_block->start() == flow()->start_bci(), "blocks out of order"); start_block->enter(); diff --git a/hotspot/src/share/vm/shark/sharkInliner.cpp b/hotspot/src/share/vm/shark/sharkInliner.cpp index c9e895a9c9b..1f4ea829fb3 100644 --- a/hotspot/src/share/vm/shark/sharkInliner.cpp +++ b/hotspot/src/share/vm/shark/sharkInliner.cpp @@ -725,7 +725,7 @@ bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) { // Push the result if necessary if (is_get) { bool result_pushed = false; - if (field->is_constant()) { + if (field->is_constant() && field->is_static()) { SharkConstant *sc = SharkConstant::for_field(iter()); if (sc->is_loaded()) { push(sc->is_nonzero()); diff --git a/hotspot/src/share/vm/shark/sharkInvariants.hpp b/hotspot/src/share/vm/shark/sharkInvariants.hpp index 50e1be8ea6d..e6b6399fe26 100644 --- a/hotspot/src/share/vm/shark/sharkInvariants.hpp +++ b/hotspot/src/share/vm/shark/sharkInvariants.hpp @@ -68,7 +68,7 @@ class SharkCompileInvariants : public ResourceObj { // // Accessing this directly is kind of ugly, so it's private. Add // new accessors below if you need something from it. - private: + protected: ciEnv* env() const { assert(_env != NULL, "env not available"); return _env; @@ -99,13 +99,15 @@ class SharkCompileInvariants : public ResourceObj { DebugInformationRecorder* debug_info() const { return env()->debug_info(); } - Dependencies* dependencies() const { - return env()->dependencies(); - } SharkCodeBuffer* code_buffer() const { return builder()->code_buffer(); } + public: + Dependencies* dependencies() const { + return env()->dependencies(); + } + // Commonly used classes protected: ciInstanceKlass* java_lang_Object_klass() const { diff --git a/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp b/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp index fcd6906caad..6614146bb42 100644 --- a/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp +++ b/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp @@ -113,7 +113,19 @@ void SharkTopLevelBlock::scan_for_traps() { ciSignature* sig; method = iter()->get_method(will_link, &sig); assert(will_link, "typeflow responsibility"); - + // We can't compile calls to method handle intrinsics, because we use + // the interpreter entry points and they expect the top frame to be an + // interpreter frame. We need to implement the intrinsics for Shark. + if (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()) { + if (SharkPerformanceWarnings) { + warning("JSR292 optimization not yet implemented in Shark"); + } + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_unhandled, + Deoptimization::Action_make_not_compilable), bci()); + return; + } if (!method->holder()->is_linked()) { set_trap( Deoptimization::make_trap_request( @@ -158,6 +170,16 @@ void SharkTopLevelBlock::scan_for_traps() { return; } break; + case Bytecodes::_invokedynamic: + case Bytecodes::_invokehandle: + if (SharkPerformanceWarnings) { + warning("JSR292 optimization not yet implemented in Shark"); + } + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_unhandled, + Deoptimization::Action_make_not_compilable), bci()); + return; } } @@ -1030,7 +1052,6 @@ ciMethod* SharkTopLevelBlock::improve_virtual_call(ciMethod* caller, dest_method->holder() == java_lang_Object_klass()) return dest_method; -#ifdef SHARK_CAN_DEOPTIMIZE_ANYWHERE // This code can replace a virtual call with a direct call if this // class is the only one in the entire set of loaded classes that // implements this method. This makes the compiled code dependent @@ -1064,6 +1085,8 @@ ciMethod* SharkTopLevelBlock::improve_virtual_call(ciMethod* caller, if (monomorphic_target != NULL) { assert(!monomorphic_target->is_abstract(), "shouldn't be"); + function()->dependencies()->assert_unique_concrete_method(actual_receiver, monomorphic_target); + // Opto has a bunch of type checking here that I don't // understand. It's to inhibit casting in one direction, // possibly because objects in Opto can have inexact @@ -1097,7 +1120,6 @@ ciMethod* SharkTopLevelBlock::improve_virtual_call(ciMethod* caller, // with non-monomorphic targets if the receiver has an exact // type. We don't mark types this way, so we can't do this. -#endif // SHARK_CAN_DEOPTIMIZE_ANYWHERE return NULL; } @@ -1298,8 +1320,9 @@ void SharkTopLevelBlock::do_call() { // Try to inline the call if (!call_is_virtual) { - if (SharkInliner::attempt_inline(call_method, current_state())) + if (SharkInliner::attempt_inline(call_method, current_state())) { return; + } } // Find the method we are calling diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp index 740912d3909..089cd3e0811 100644 --- a/hotspot/src/share/vm/utilities/exceptions.hpp +++ b/hotspot/src/share/vm/utilities/exceptions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -267,6 +267,7 @@ class Exceptions { #define THROW_WRAPPED_0(name, oop_to_wrap) THROW_WRAPPED_(name, oop_to_wrap, 0) #define THROW_ARG_0(name, signature, arg) THROW_ARG_(name, signature, arg, 0) #define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0) +#define THROW_MSG_CAUSE_NULL(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, NULL) #define THROW_NULL(name) THROW_(name, NULL) #define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, NULL) diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index e00be90320e..5c10cf018be 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -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 @@ -1250,6 +1250,14 @@ inline int build_int_from_shorts( jushort low, jushort high ) { #define PTR64_FORMAT "0x%016" PRIx64 +// Format jlong, if necessary +#ifndef JLONG_FORMAT +#define JLONG_FORMAT INT64_FORMAT +#endif +#ifndef JULONG_FORMAT +#define JULONG_FORMAT UINT64_FORMAT +#endif + // Format pointers which change size between 32- and 64-bit. #ifdef _LP64 #define INTPTR_FORMAT "0x%016" PRIxPTR diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index e103816de93..a69708f8c8f 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -306,4 +306,8 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #endif #define offsetof(klass,field) offset_of(klass,field) +#if defined(_LP64) && defined(__APPLE__) +#define JLONG_FORMAT "%ld" +#endif // _LP64 && __APPLE__ + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 2b6e2eeb853..ea0a0c25bec 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -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 @@ -243,13 +243,11 @@ outputStream& outputStream::indent() { } void outputStream::print_jlong(jlong value) { - // N.B. Same as INT64_FORMAT - print(os::jlong_format_specifier(), value); + print(JLONG_FORMAT, value); } void outputStream::print_julong(julong value) { - // N.B. Same as UINT64_FORMAT - print(os::julong_format_specifier(), value); + print(JULONG_FORMAT, value); } /** diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp index fbb035adf0c..862c9b304fb 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.cpp +++ b/hotspot/src/share/vm/utilities/taskqueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -239,8 +239,8 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) { #ifdef TRACESPINNING void ParallelTaskTerminator::print_termination_counts() { - gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld " - "Total spins: %lld Total peeks: %lld", + gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: " UINT32_FORMAT + " Total spins: " UINT32_FORMAT " Total peeks: " UINT32_FORMAT, total_yields(), total_spins(), total_peeks()); diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index ddb6e1cf882..d8fe93b64f3 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -702,7 +702,7 @@ void VMError::report(outputStream* st) { if (_verbose && Universe::is_fully_initialized()) { // print code cache information before vm abort - CodeCache::print_bounds(st); + CodeCache::print_summary(st); st->cr(); } diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile index c8efce4276c..7bd42a1e28a 100644 --- a/hotspot/test/Makefile +++ b/hotspot/test/Makefile @@ -189,9 +189,9 @@ jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) $(JTREG) -a -v:fail,error \ $(JTREG_KEY_OPTION) \ $(EXTRA_JTREG_OPTIONS) \ - -r:$(ABS_TEST_OUTPUT_DIR)/JTreport \ - -w:$(ABS_TEST_OUTPUT_DIR)/JTwork \ - -jdk:$(PRODUCT_HOME) \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ $(JAVA_OPTIONS:%=-vmoption:%) \ $(JTREG_TESTDIRS) \ || $(BUNDLE_UP_FAILED) diff --git a/hotspot/test/compiler/6896617/Test6896617.java b/hotspot/test/compiler/6896617/Test6896617.java new file mode 100644 index 00000000000..e28d3d7d57b --- /dev/null +++ b/hotspot/test/compiler/6896617/Test6896617.java @@ -0,0 +1,331 @@ +/* + * 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 6896617 + * @summary Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() with SSE instructions on x86 + * @run main/othervm/timeout=1200 -Xbatch -Xmx256m Test6896617 + * + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; + +public class Test6896617 { + final static int SIZE = 256; + + public static void main(String[] args) { + String csn = "ISO-8859-1"; + Charset cs = Charset.forName(csn); + CharsetEncoder enc = cs.newEncoder(); + enc.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetDecoder dec = cs.newDecoder(); + dec.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + byte repl = (byte)'?'; + enc.replaceWith(new byte[] { repl }); + + // Use internal API for tests. + sun.nio.cs.ArrayEncoder arrenc = (sun.nio.cs.ArrayEncoder)enc; + sun.nio.cs.ArrayDecoder arrdec = (sun.nio.cs.ArrayDecoder)dec; + + // Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF) + Random rnd = new Random(0); + int maxchar = 0xFF; + char[] a = new char[SIZE]; + byte[] b = new byte[SIZE]; + char[] at = new char[SIZE]; + byte[] bt = new byte[SIZE]; + for (int i = 0; i < SIZE; i++) { + char c = (char) rnd.nextInt(maxchar); + if (!enc.canEncode(c)) { + System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); + System.exit(97); + } + a[i] = c; + b[i] = (byte)c; + at[i] = (char)-1; + bt[i] = (byte)-1; + } + if (arrenc.encode(a, 0, SIZE, bt) != SIZE || !Arrays.equals(b, bt)) { + System.out.println("Something wrong: ArrayEncoder.encode failed"); + System.exit(97); + } + if (arrdec.decode(b, 0, SIZE, at) != SIZE || !Arrays.equals(a, at)) { + System.out.println("Something wrong: ArrayDecoder.decode failed"); + System.exit(97); + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char)-1; + bt[i] = (byte)-1; + } + + ByteBuffer bb = ByteBuffer.wrap(b); + CharBuffer ba = CharBuffer.wrap(a); + ByteBuffer bbt = ByteBuffer.wrap(bt); + CharBuffer bat = CharBuffer.wrap(at); + if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) { + System.out.println("Something wrong: Encoder.encode failed"); + System.exit(97); + } + if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) { + System.out.println("Something wrong: Decoder.decode failed"); + System.exit(97); + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char)-1; + bt[i] = (byte)-1; + } + + // Warm up + boolean failed = false; + int result = 0; + for (int i = 0; i < 10000; i++) { + result += arrenc.encode(a, 0, SIZE, bt); + result -= arrdec.decode(b, 0, SIZE, at); + } + for (int i = 0; i < 10000; i++) { + result += arrenc.encode(a, 0, SIZE, bt); + result -= arrdec.decode(b, 0, SIZE, at); + } + for (int i = 0; i < 10000; i++) { + result += arrenc.encode(a, 0, SIZE, bt); + result -= arrdec.decode(b, 0, SIZE, at); + } + if (result != 0 || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { + failed = true; + System.out.println("Failed: ArrayEncoder.encode char[" + SIZE + "] and ArrayDecoder.decode byte[" + SIZE + "]"); + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char)-1; + bt[i] = (byte)-1; + } + + boolean is_underflow = true; + for (int i = 0; i < 10000; i++) { + ba.clear(); bb.clear(); bat.clear(); bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char)-1; + bt[i] = (byte)-1; + } + for (int i = 0; i < 10000; i++) { + ba.clear(); bb.clear(); bat.clear(); bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char)-1; + bt[i] = (byte)-1; + } + for (int i = 0; i < 10000; i++) { + ba.clear(); bb.clear(); bat.clear(); bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + if (!is_underflow || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { + failed = true; + System.out.println("Failed: Encoder.encode char[" + SIZE + "] and Decoder.decode byte[" + SIZE + "]"); + } + + // Test encoder with different source and destination sizes + System.out.println("Testing different source and destination sizes"); + for (int i = 1; i <= SIZE; i++) { + for (int j = 1; j <= SIZE; j++) { + bt = new byte[j]; + // very source's SIZE + result = arrenc.encode(a, 0, i, bt); + int l = Math.min(i, j); + if (result != l) { + failed = true; + System.out.println("Failed: encode char[" + i + "] to byte[" + j + "]: result = " + result + ", expected " + l); + } + for (int k = 0; k < l; k++) { + if (bt[k] != b[k]) { + failed = true; + System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); + } + } + // very source's offset + int sz = SIZE - i + 1; + result = arrenc.encode(a, i-1, sz, bt); + l = Math.min(sz, j); + if (result != l) { + failed = true; + System.out.println("Failed: encode char[" + sz + "] to byte[" + j + "]: result = " + result + ", expected " + l); + } + for (int k = 0; k < l; k++) { + if (bt[k] != b[i+k-1]) { + failed = true; + System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[i+k-1]); + } + } + } + } + + // Test encoder with char > 0xFF + System.out.println("Testing big char"); + + byte orig = (byte)'A'; + bt = new byte[SIZE]; + for (int i = 1; i <= SIZE; i++) { + for (int j = 0; j < i; j++) { + a[j] += 0x100; + // make sure to replace a different byte + bt[j] = orig; + result = arrenc.encode(a, 0, i, bt); + if (result != i) { + failed = true; + System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: result = " + result + ", expected " + i); + } + if (bt[j] != repl) { + failed = true; + System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl); + } + bt[j] = b[j]; // Restore to compare whole array + for (int k = 0; k < i; k++) { + if (bt[k] != b[k]) { + failed = true; + System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); + } + } + a[j] -= 0x100; // Restore + } + } + + // Test sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() performance. + + int itrs = Integer.getInteger("iterations", 1000000); + int size = Integer.getInteger("size", 256); + a = new char[size]; + b = new byte[size]; + bt = new byte[size]; + for (int i = 0; i < size; i++) { + char c = (char) rnd.nextInt(maxchar); + if (!enc.canEncode(c)) { + System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); + System.exit(97); + } + a[i] = c; + b[i] = (byte)-1; + bt[i] = (byte)c; + } + ba = CharBuffer.wrap(a); + bb = ByteBuffer.wrap(b); + boolean enc_res = enc.encode(ba, bb, true).isUnderflow(); + if (!enc_res || !Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed 1: Encoder.encode char[" + size + "]"); + } + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + + // Make sure to recompile method if needed before performance run. + for (int i = 0; i < 10000; i++) { + ba.clear(); bb.clear(); + enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); + } + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + for (int i = 0; i < 10000; i++) { + ba.clear(); bb.clear(); + enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); + } + if (!enc_res || !Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed 2: Encoder.encode char[" + size + "]"); + } + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + + System.out.println("Testing ISO_8859_1$Encode.encodeArrayLoop() performance"); + long start = System.currentTimeMillis(); + for (int i = 0; i < itrs; i++) { + ba.clear(); bb.clear(); + enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); + } + long end = System.currentTimeMillis(); + if (!enc_res || !Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed 3: Encoder.encode char[" + size + "]"); + } else { + System.out.println("size: " + size + " time: " + (end - start)); + } + + // Test sun.nio.cs.ISO_8859_1$Encode.encode() performance. + + // Make sure to recompile method if needed before performance run. + result = 0; + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + for (int i = 0; i < 10000; i++) { + result += arrenc.encode(a, 0, size, b); + } + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + for (int i = 0; i < 10000; i++) { + result += arrenc.encode(a, 0, size, b); + } + if (result != size*20000 || !Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed 1: ArrayEncoder.encode char[" + SIZE + "]"); + } + for (int i = 0; i < size; i++) { + b[i] = (byte)-1; + } + + System.out.println("Testing ISO_8859_1$Encode.encode() performance"); + result = 0; + start = System.currentTimeMillis(); + for (int i = 0; i < itrs; i++) { + result += arrenc.encode(a, 0, size, b); + } + end = System.currentTimeMillis(); + if (!Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed 2: ArrayEncoder.encode char[" + size + "]"); + } else { + System.out.println("size: " + size + " time: " + (end - start)); + } + + if (failed) { + System.out.println("FAILED"); + System.exit(97); + } + System.out.println("PASSED"); + } +} diff --git a/hotspot/test/compiler/7190310/Test7190310.java b/hotspot/test/compiler/7190310/Test7190310.java index 57a89b93b39..b45c60bf196 100644 --- a/hotspot/test/compiler/7190310/Test7190310.java +++ b/hotspot/test/compiler/7190310/Test7190310.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,7 +23,16 @@ */ /* - * Manual test + * @test + * @bug 7190310 + * @summary Inlining WeakReference.get(), and hoisting $referent may lead to non-terminating loops + * @run main/othervm/timeout=600 -Xbatch Test7190310 + */ + +/* + * Note bug exhibits as infinite loop, timeout is helpful. + * It should normally finish pretty quickly, but on some especially slow machines + * it may not. The companion _unsafe test lacks a timeout, but that is okay. */ import java.lang.ref.*; diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 4d8f24840a0..25b3727d9e6 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -195,3 +195,4 @@ b854e70084214e9dcf1b37373f6e4b1a68760e03 jdk8-b68 499be952a291cec1dc774a84a238941d6faf772d jdk8-b71 bdf2af722a6b54fca47d8c51d17a1b8f41dd7a3e jdk8-b72 84946404d1e1de003ed2bf218ef8d48906a90e37 jdk8-b73 +2087e24a4357eceb6432e94918e75fdc706a27d6 jdk8-b74 diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/Constants.java b/jaxp/src/com/sun/org/apache/bcel/internal/Constants.java index ac4ae3e3e37..d7fc6bcedf0 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/Constants.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/Constants.java @@ -746,27 +746,29 @@ public interface Constants { /** Attributes and their corresponding names. */ - public static final byte ATTR_UNKNOWN = -1; - public static final byte ATTR_SOURCE_FILE = 0; - public static final byte ATTR_CONSTANT_VALUE = 1; - public static final byte ATTR_CODE = 2; - public static final byte ATTR_EXCEPTIONS = 3; - public static final byte ATTR_LINE_NUMBER_TABLE = 4; - public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5; - public static final byte ATTR_INNER_CLASSES = 6; - public static final byte ATTR_SYNTHETIC = 7; - public static final byte ATTR_DEPRECATED = 8; - public static final byte ATTR_PMG = 9; - public static final byte ATTR_SIGNATURE = 10; - public static final byte ATTR_STACK_MAP = 11; + public static final byte ATTR_UNKNOWN = -1; + public static final byte ATTR_SOURCE_FILE = 0; + public static final byte ATTR_CONSTANT_VALUE = 1; + public static final byte ATTR_CODE = 2; + public static final byte ATTR_EXCEPTIONS = 3; + public static final byte ATTR_LINE_NUMBER_TABLE = 4; + public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5; + public static final byte ATTR_INNER_CLASSES = 6; + public static final byte ATTR_SYNTHETIC = 7; + public static final byte ATTR_DEPRECATED = 8; + public static final byte ATTR_PMG = 9; + public static final byte ATTR_SIGNATURE = 10; + public static final byte ATTR_STACK_MAP = 11; + public static final byte ATTR_LOCAL_VARIABLE_TYPE_TABLE = 12; - public static final short KNOWN_ATTRIBUTES = 12; + public static final short KNOWN_ATTRIBUTES = 13; public static final String[] ATTRIBUTE_NAMES = { "SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", "InnerClasses", "Synthetic", "Deprecated", - "PMGClass", "Signature", "StackMap" + "PMGClass", "Signature", "StackMap", + "LocalVariableTypeTable" }; /** Constants used in the StackMap attribute. diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Attribute.java b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Attribute.java index a391d4d639a..204bb2506bb 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Attribute.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Attribute.java @@ -206,6 +206,9 @@ public abstract class Attribute implements Cloneable, Node, Serializable { case Constants.ATTR_LOCAL_VARIABLE_TABLE: return new LocalVariableTable(name_index, length, file, constant_pool); + case Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE: + return new LocalVariableTypeTable(name_index, length, file, constant_pool); + case Constants.ATTR_INNER_CLASSES: return new InnerClasses(name_index, length, file, constant_pool); diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java index c25cce0555b..fe35197652d 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java @@ -210,6 +210,12 @@ public class DescendingVisitor implements Visitor { stack.pop(); } + public void visitLocalVariableTypeTable(LocalVariableTypeTable obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + public void visitStackMap(StackMap table) { stack.push(table); table.accept(visitor); diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java index 88fe11e6a8a..32a1cc144cf 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java @@ -98,6 +98,7 @@ public class EmptyVisitor implements Visitor { public void visitLineNumberTable(LineNumberTable obj) {} public void visitLocalVariable(LocalVariable obj) {} public void visitLocalVariableTable(LocalVariableTable obj) {} + public void visitLocalVariableTypeTable(LocalVariableTypeTable obj) {} public void visitMethod(Method obj) {} public void visitSignature(Signature obj) {} public void visitSourceFile(SourceFile obj) {} diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java new file mode 100644 index 00000000000..472f53a2b6f --- /dev/null +++ b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java @@ -0,0 +1,146 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +package com.sun.org.apache.bcel.internal.classfile; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.sun.org.apache.bcel.internal.Constants; +import java.io.*; + +// The new table is used when generic types are about... + +//LocalVariableTable_attribute { +// u2 attribute_name_index; +// u4 attribute_length; +// u2 local_variable_table_length; +// { u2 start_pc; +// u2 length; +// u2 name_index; +// u2 descriptor_index; +// u2 index; +// } local_variable_table[local_variable_table_length]; +// } + +//LocalVariableTypeTable_attribute { +// u2 attribute_name_index; +// u4 attribute_length; +// u2 local_variable_type_table_length; +// { +// u2 start_pc; +// u2 length; +// u2 name_index; +// u2 signature_index; +// u2 index; +// } local_variable_type_table[local_variable_type_table_length]; +// } +// J5TODO: Needs some testing ! +public class LocalVariableTypeTable extends Attribute { + private static final long serialVersionUID = -1082157891095177114L; +private int local_variable_type_table_length; // Table of local + private LocalVariable[] local_variable_type_table; // variables + + public LocalVariableTypeTable(LocalVariableTypeTable c) { + this(c.getNameIndex(), c.getLength(), c.getLocalVariableTypeTable(), + c.getConstantPool()); + } + + public LocalVariableTypeTable(int name_index, int length, + LocalVariable[] local_variable_table, + ConstantPool constant_pool) + { + super(Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE, name_index, length, constant_pool); + setLocalVariableTable(local_variable_table); + } + + LocalVariableTypeTable(int nameIdx, int len, DataInputStream dis,ConstantPool cpool) throws IOException { + this(nameIdx, len, (LocalVariable[])null, cpool); + + local_variable_type_table_length = (dis.readUnsignedShort()); + local_variable_type_table = new LocalVariable[local_variable_type_table_length]; + + for(int i=0; i < local_variable_type_table_length; i++) + local_variable_type_table[i] = new LocalVariable(dis, cpool); + } + + @Override +public void accept(Visitor v) { + v.visitLocalVariableTypeTable(this); + } + + @Override +public final void dump(DataOutputStream file) throws IOException + { + super.dump(file); + file.writeShort(local_variable_type_table_length); + for(int i=0; i < local_variable_type_table_length; i++) + local_variable_type_table[i].dump(file); + } + + public final LocalVariable[] getLocalVariableTypeTable() { + return local_variable_type_table; + } + + public final LocalVariable getLocalVariable(int index) { + for(int i=0; i < local_variable_type_table_length; i++) + if(local_variable_type_table[i].getIndex() == index) + return local_variable_type_table[i]; + + return null; + } + + public final void setLocalVariableTable(LocalVariable[] local_variable_table) + { + this.local_variable_type_table = local_variable_table; + local_variable_type_table_length = (local_variable_table == null)? 0 : + local_variable_table.length; + } + + /** + * @return String representation. + */ + @Override +public final String toString() { + StringBuilder buf = new StringBuilder(); + + for(int i=0; i < local_variable_type_table_length; i++) { + buf.append(local_variable_type_table[i].toString()); + + if(i < local_variable_type_table_length - 1) buf.append('\n'); + } + + return buf.toString(); + } + + /** + * @return deep copy of this attribute + */ + @Override +public Attribute copy(ConstantPool constant_pool) { + LocalVariableTypeTable c = (LocalVariableTypeTable)clone(); + + c.local_variable_type_table = new LocalVariable[local_variable_type_table_length]; + for(int i=0; i < local_variable_type_table_length; i++) + c.local_variable_type_table[i] = local_variable_type_table[i].copy(); + + c.constant_pool = constant_pool; + return c; + } + + public final int getTableLength() { return local_variable_type_table_length; } +} diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Visitor.java b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Visitor.java index a66c7ad2927..a076768700c 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Visitor.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/classfile/Visitor.java @@ -94,6 +94,7 @@ public interface Visitor { public void visitLineNumberTable(LineNumberTable obj); public void visitLocalVariable(LocalVariable obj); public void visitLocalVariableTable(LocalVariableTable obj); + public void visitLocalVariableTypeTable(LocalVariableTypeTable obj); public void visitMethod(Method obj); public void visitSignature(Signature obj); public void visitSourceFile(SourceFile obj); diff --git a/jaxp/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java b/jaxp/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java index a58172a9114..34da00768cd 100644 --- a/jaxp/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java +++ b/jaxp/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java @@ -258,6 +258,23 @@ public class MethodGen extends FieldGenOrMethodGen { addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end); } + } else if (a instanceof LocalVariableTypeTable) { + LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable(); + removeLocalVariables(); + for (int k = 0; k < lv.length; k++) { + LocalVariable l = lv[k]; + InstructionHandle start = il.findHandle(l.getStartPC()); + InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength()); + // Repair malformed handles + if (null == start) { + start = il.getStart(); + } + if (null == end) { + end = il.getEnd(); + } + addLocalVariable(l.getName(), Type.getType(l.getSignature()), l + .getIndex(), start, end); + } } else addCodeAttribute(a); } diff --git a/jaxws/.hgtags b/jaxws/.hgtags index f4bf9b21b81..1ae97b3df38 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -195,3 +195,4 @@ d3fe408f3a9ad250bc9a4e9365bdfc3f28c1d3f4 jdk8-b68 f577a39c9fb3d5820248c13c2cc74a192a9313e0 jdk8-b71 d9707230294d54e695e745a90de6112909100f12 jdk8-b72 c606f644a5d9118c14b5822738bf23c300f14f24 jdk8-b73 +12db3c5a3393b03eeb09ff26f418c4420c21aaab jdk8-b74 diff --git a/jdk/.hgtags b/jdk/.hgtags index e774b097c5e..dbc8d128f1f 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -195,3 +195,4 @@ a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70 2a5af0f766d0acd68a81fb08fe11fd66795f86af jdk8-b71 32a57e645e012a1f0665c075969ca598e0dbb948 jdk8-b72 733885f57e14cc27f5a5ff0dffe641d2fa3c704a jdk8-b73 +57d5d954462831ac353a1f40d3bb05ddb4620952 jdk8-b74 diff --git a/jdk/make/Makefile b/jdk/make/Makefile index ceb1492bb4e..c2db5a816a2 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -237,6 +237,9 @@ SUBDIRS = tools java javax sun com jdk ifeq ($(PLATFORM), macosx) SUBDIRS += apple endif +ifeq ($(PLATFORM), windows) + SUBDIRS += bridge +endif SUBDIRS_tools = launchers SUBDIRS_misc = org jpda diff --git a/jdk/make/bridge/AccessBridgeJava/Makefile b/jdk/make/bridge/AccessBridgeJava/Makefile new file mode 100644 index 00000000000..c5bebd02cea --- /dev/null +++ b/jdk/make/bridge/AccessBridgeJava/Makefile @@ -0,0 +1,93 @@ +# +# 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. 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. +# + +# +# Makefile for building AccessBridge +# +BUILDDIR = ../.. +PRODUCT = java +PACKAGE = com.sun.java.accessibility + +include $(BUILDDIR)/common/Defs.gmk +JARFILE = $(EXTDIR)/access-bridge$(ABSUFFIX).jar + +ifeq ($(ARCH_DATA_MODEL), 64) + ABPLATFORM = 64bit + ABSUFFIX = -64 +else +ifeq ($(ARCH_DATA_MODEL), 32) +ifdef ABLEGACY + ABSUFFIX = + ABPLATFORM = legacy +else + ABPLATFORM = 32bit + ABSUFFIX = -32 +endif +endif +endif + +# +# Java files to compile. +# +FILES_java = com/sun/java/accessibility/AccessBridge.java + +# +# Location for the newly built classfiles. +# +CLASSDESTDIR = $(TEMPDIR)/classes + +# +# Rules +# +CLASSDESTDIR = $(TEMPDIR)/classes + +FILES_class = $(FILES_java:%.java=$(CLASSDESTDIR)/%.class) + +build: prebuild + +prebuild: + $(CP) $(CLOSED_PLATFORM_SRC)/classes/com/sun/java/accessibility/$(ABPLATFORM)/AccessBridge.java \ + $(CLOSED_PLATFORM_SRC)/classes/com/sun/java/accessibility + +all : build $(JARFILE) + +# +# JAR file +# +$(JARFILE): \ + $(FILES_class) + $(BOOT_JAR_CMD) -cf $(JARFILE) \ + -C $(CLASSDESTDIR) com \ + $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +clean clobber:: + $(RM) -r $(CLASSDESTDIR) \ + $(EXTDIR)/$(JARFILE) diff --git a/jdk/make/bridge/JAWTAccessBridge/Files_cpp.gmk b/jdk/make/bridge/JAWTAccessBridge/Files_cpp.gmk new file mode 100644 index 00000000000..5527f825b9f --- /dev/null +++ b/jdk/make/bridge/JAWTAccessBridge/Files_cpp.gmk @@ -0,0 +1,29 @@ +# +# 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. 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. +# + +# +# Native files to compile. +FILES_cpp = \ + JAWTAccessBridge.cpp diff --git a/jdk/make/bridge/JAWTAccessBridge/Makefile b/jdk/make/bridge/JAWTAccessBridge/Makefile new file mode 100644 index 00000000000..7ca80afdbf7 --- /dev/null +++ b/jdk/make/bridge/JAWTAccessBridge/Makefile @@ -0,0 +1,69 @@ +# +# 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. 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. +# + +# +# Makefile for building JAWTAccessBridge +# + +BUILDDIR = ../.. +LIBRARY = JAWTAccessBridge$(ABSUFFIX) +include $(BUILDDIR)/common/Defs.gmk + +# Indicate we want the C++ compiler to do the linking. +CPLUSPLUSLIBRARY=true + +ifeq ($(ARCH_DATA_MODEL), 64) + ABSUFFIX = -64 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_64 + ABRIDGE_MACHINE=X64 +else +ifeq ($(ARCH_DATA_MODEL), 32) + ABRIDGE_MACHINE=I386 +ifdef ABLEGACY + ABSUFFIX = + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_LEGACY +else + ABSUFFIX = -32 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_32 +endif +endif +endif + +include FILES_cpp.gmk + +VERSIONINFO_RESOURCE = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeStatusWindow.rc + +OTHER_CPPFLAGS += -D$(ACCESSBRIDGE_ARCH) -I "$(INCLUDEDIR)" -I "$(PLATFORM_INCLUDE)" +LDLIBS += kernel32.lib user32.lib gdi32.lib winspool.lib jawt.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \ + uuid.lib odbc32.lib odbccp32.lib /subsystem:windows /dll /incremental:no /machine:$(ABRIDGE_MACHINE) \ + /def:$(CLOSED_PLATFORM_SRC)/native/sun/bridge/JAWTAccessBridge.DEF /libpath:"$(LIBDIR)" + +# +# Rules +# +include $(BUILDDIR)/common/Library.gmk + +vpath %.cpp $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.RC $(CLOSED_PLATFORM_SRC)/native/sun/bridge diff --git a/jdk/make/bridge/Jabswitch/Makefile b/jdk/make/bridge/Jabswitch/Makefile new file mode 100644 index 00000000000..efd65e07a42 --- /dev/null +++ b/jdk/make/bridge/Jabswitch/Makefile @@ -0,0 +1,63 @@ +# +# 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. 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. +# + +# +# Makefile for building jabswitch.exe +# + +BUILDDIR = ../.. +PROGRAM = jabswitch +include $(BUILDDIR)/common/Defs.gmk + +# Indicate we want the C++ compiler to do the linking. +CPLUSPLUSLIBRARY=true + +VERSIONINFO_RESOURCE = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeStatusWindow.rc +VERSIONRES = $(TEMPDIR)/AccessBridgeStatusWindow.res + +JAB_EXE= $(TEMPDIR)/jabswitch.exe + +JAB_SRC = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/jabswitch.cpp + +JAB_MANIFEST_INP = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/jabswitch.manifest +JAB_MANIFEST_OUT = $(TEMPDIR)/jabswitch.exe.intermediate.manifest + +RC_FLAGS += /fo "$(VERSIONRES)" +OTHER_CPPFLAGS += /MD /Fo"$(TEMPDIR)/" /Fd"$(TEMPDIR)/" /analyze- /Od /Gd /nologo /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /RTC1 /W3 /ZI /Zc:wchar_t /EHsc +LDDFLAGS += Advapi32.lib Version.lib User32.lib + +all: buildexe copyfilejab + +buildexe : + $(CD) $(TEMPDIR) + $(RC) $(RC_FLAGS) $(VERSIONINFO_RESOURCE) + $(CC) $(CPPFLAGS) $(JAB_SRC) $(LDDFLAGS) $(VERSIONRES) -o $(JAB_EXE) + $(MT) /nologo /verbose /manifest $(JAB_MANIFEST_INP) /outputresource:$(JAB_EXE) + +copyfilejab : + $(CP) $(JAB_EXE) $(BINDIR) + +vpath %.cpp $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.rc $(CLOSED_PLATFORM_SRC)/native/sun/bridge diff --git a/jdk/make/bridge/Jaccess/Makefile b/jdk/make/bridge/Jaccess/Makefile new file mode 100644 index 00000000000..df57536943e --- /dev/null +++ b/jdk/make/bridge/Jaccess/Makefile @@ -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. 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. +# + +# +# Makefile for building jaccess +# +BUILDDIR = ../.. +PRODUCT = java +PACKAGE = com.sun.java.accessibility.jaccess + +include $(BUILDDIR)/common/Defs.gmk +JARFILE = $(EXTDIR)/jaccess.jar + +# +# Java files to compile. +# +#AUTO_FILES_JAVA_DIRS = $(CLOSED_PLATFORM_SRC)/bridge +FILES_java = \ + com/sun/java/accessibility/util/AccessibilityEventMonitor.java \ + com/sun/java/accessibility/util/AccessibilityListenerList.java \ + com/sun/java/accessibility/util/AWTEventMonitor.java \ + com/sun/java/accessibility/util/EventID.java \ + com/sun/java/accessibility/util/EventQueueMonitor.java \ + com/sun/java/accessibility/util/GUIInitializedListener.java \ + com/sun/java/accessibility/util/GUIInitializedMulticaster.java \ + com/sun/java/accessibility/util/SwingEventMonitor.java \ + com/sun/java/accessibility/util/TopLevelWindowListener.java \ + com/sun/java/accessibility/util/TopLevelWindowMulticaster.java \ + com/sun/java/accessibility/util/Translator.java \ + com/sun/java/accessibility/util/java/awt/ButtonTranslator.java \ + com/sun/java/accessibility/util/java/awt/CheckboxTranslator.java \ + com/sun/java/accessibility/util/java/awt/LabelTranslator.java \ + com/sun/java/accessibility/util/java/awt/ListTranslator.java \ + com/sun/java/accessibility/util/java/awt/TextComponentTranslator.java + +# +# Rules +# +CLASSDESTDIR = $(TEMPDIR)/classes + +FILES_class = $(FILES_java:%.java=$(CLASSDESTDIR)/%.class) + +all : build $(JARFILE) + +# +# JAR file +# +$(JARFILE): \ + $(FILES_class) + $(BOOT_JAR_CMD) -cf $(JARFILE) \ + -C $(CLASSDESTDIR) com \ + $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) + + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +clean clobber:: + $(RM) -r $(CLASSDESTDIR) \ + $(EXTDIR)/$(JARFILE) diff --git a/jdk/make/bridge/JavaAccessBridge/Files_cpp.gmk b/jdk/make/bridge/JavaAccessBridge/Files_cpp.gmk new file mode 100644 index 00000000000..3d197be7d4b --- /dev/null +++ b/jdk/make/bridge/JavaAccessBridge/Files_cpp.gmk @@ -0,0 +1,33 @@ +# +# 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. 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. +# + +# +# Native files to compile. +FILES_cpp = \ + AccessBridgeATInstance.cpp \ + AccessBridgeDebug.cpp \ + AccessBridgeJavaEntryPoints.cpp \ + AccessBridgeMessages.cpp \ + JavaAccessBridge.cpp diff --git a/jdk/make/bridge/JavaAccessBridge/Makefile b/jdk/make/bridge/JavaAccessBridge/Makefile new file mode 100644 index 00000000000..6637a777326 --- /dev/null +++ b/jdk/make/bridge/JavaAccessBridge/Makefile @@ -0,0 +1,90 @@ +# +# 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. 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. +# + +# +# Makefile for building JavaAccessBridge.DLL +# + +BUILDDIR = ../.. +LIBRARY = JavaAccessBridge$(ABSUFFIX) +include $(BUILDDIR)/common/Defs.gmk + +# Indicate we want the C++ compiler to do the linking. +CPLUSPLUSLIBRARY=true + +ifeq ($(ARCH_DATA_MODEL), 64) + ABSUFFIX = -64 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_64 + ABRIDGE_MACHINE=X64 +else +ifeq ($(ARCH_DATA_MODEL), 32) + ABRIDGE_MACHINE=I386 +ifdef ABLEGACY + ABSUFFIX = + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_LEGACY +else + ABSUFFIX = -32 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_32 +endif +endif +endif + +include FILES_cpp.gmk + +PLATFORM_INCLUDE_BRIDGE = $(PLATFORM_INCLUDE)/bridge + +VERSIONINFO_RESOURCE = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeStatusWindow.rc + +OTHER_CPPFLAGS += -D$(ACCESSBRIDGE_ARCH) -I "$(INCLUDEDIR)" -I "$(PLATFORM_INCLUDE)" +LDLIBS += kernel32.lib user32.lib gdi32.lib winspool.lib jawt.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \ + odbc32.lib odbccp32.lib /subsystem:windows /dll /incremental:no /machine:$(ABRIDGE_MACHINE) \ + /def:$(CLOSED_PLATFORM_SRC)/native/sun/bridge/JavaAccessBridge.DEF /libpath:"$(LIBDIR)" + +all : build postbuild + +postbuild : + $(MKDIR) -p $(PLATFORM_INCLUDE_BRIDGE) + $(CP) $(CLOSED_PLATFORM_SRC)/native/sun/bridge/accessibility.properties $(LIBDIR) + $(CP) $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeCallbacks.h $(PLATFORM_INCLUDE_BRIDGE) + $(CP) $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeCalls.h $(PLATFORM_INCLUDE_BRIDGE) + $(CP) $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgePackages.h $(PLATFORM_INCLUDE_BRIDGE) + $(CP) $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeCalls.c $(PLATFORM_INCLUDE_BRIDGE) + +# +# Rules +# +include $(BUILDDIR)/common/Library.gmk + +vpath %.cpp $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.DEF $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.rc $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.c $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.h $(CLOSED_PLATFORM_SRC)/native/sun/bridge + +# +# Extra clean rule. +# +clean clobber:: + $(RM) $(FILES_h) diff --git a/jdk/make/bridge/Makefile b/jdk/make/bridge/Makefile new file mode 100644 index 00000000000..6703a21d753 --- /dev/null +++ b/jdk/make/bridge/Makefile @@ -0,0 +1,65 @@ +# +# 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. 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. +# + +# +# Makefile for building Java Access Bridge +# + +BUILDDIR = .. +include $(BUILDDIR)/common/Defs.gmk + +# +# +ifndef OPENJDK +ifeq ($(PLATFORM), windows) +include $(BUILDDIR)/common/Subdirs.gmk + +# +# build for 32 and 64 bit (new api) +# +SUBDIRS = Jaccess JavaAccessBridge WindowsAccessBridge JAWTAccessBridge AccessBridgeJava Jabswitch +# +# build for legacy +# +ifeq ($(ARCH_DATA_MODEL), 32) +OTHERSUBDIRS_MAKEFLAGS += ABLEGACY=true +OTHERSUBDIRS = JavaAccessBridge WindowsAccessBridge JAWTAccessBridge AccessBridgeJava +endif + +ifeq ($(ARCH_DATA_MODEL), 32) +all build clean clobber :: + $(SUBDIRS-loop) + $(OTHERSUBDIRS-loop) +else +all build clean clobber :: + $(SUBDIRS-loop) +endif + +clean:: + $(RM) -r $(CLASSBINDIR) $(CLASSBINDIR) + +endif # PLATFORM +endif #OPENJDK + diff --git a/jdk/make/bridge/WindowsAccessBridge/Files_cpp.gmk b/jdk/make/bridge/WindowsAccessBridge/Files_cpp.gmk new file mode 100644 index 00000000000..411e2830153 --- /dev/null +++ b/jdk/make/bridge/WindowsAccessBridge/Files_cpp.gmk @@ -0,0 +1,35 @@ +# +# 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. 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. +# + +# +# Native files to compile. +FILES_cpp = \ + AccessBridgeJavaVMInstance.cpp \ + AccessBridgeMessageQueue.cpp \ + AccessBridgeMessages.cpp \ + AccessBridgeWindowsEntryPoints.cpp \ + WinAccessBridge.cpp \ + AccessBridgeDebug.cpp \ + AccessBridgeEventHandler.cpp diff --git a/jdk/make/bridge/WindowsAccessBridge/Makefile b/jdk/make/bridge/WindowsAccessBridge/Makefile new file mode 100644 index 00000000000..f65f704e3ea --- /dev/null +++ b/jdk/make/bridge/WindowsAccessBridge/Makefile @@ -0,0 +1,71 @@ +# +# 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. 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. +# + +# +# Makefile for building WindowsAccessBridge.dll +# + +BUILDDIR = ../.. +LIBRARY = WindowsAccessBridge$(ABSUFFIX) +include $(BUILDDIR)/common/Defs.gmk + +# Indicate we want the C++ compiler to do the linking. +CPLUSPLUSLIBRARY=true + +ifeq ($(ARCH_DATA_MODEL), 64) + ABSUFFIX = -64 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_64 + ABRIDGE_MACHINE=X64 +else +ifeq ($(ARCH_DATA_MODEL), 32) + ABRIDGE_MACHINE=I386 +ifdef ABLEGACY + ABSUFFIX = + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_LEGACY +else + ABSUFFIX = -32 + ACCESSBRIDGE_ARCH = ACCESSBRIDGE_ARCH_32 +endif +endif +endif + +include FILES_cpp.gmk + +VERSIONINFO_RESOURCE = $(CLOSED_PLATFORM_SRC)/native/sun/bridge/AccessBridgeStatusWindow.rc + +OTHER_CPPFLAGS += -MT -D$(ACCESSBRIDGE_ARCH) -I "$(INCLUDEDIR)" -I "$(PLATFORM_INCLUDE)" +LDLIBS += kernel32.lib user32.lib gdi32.lib winspool.lib jawt.lib comdlg32.lib advapi32.lib shell32.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /subsystem:windows /dll /incremental:no /machine:$(ABRIDGE_MACHINE) \ + /def:$(CLOSED_PLATFORM_SRC)/native/sun/bridge/WinAccessBridge.DEF /libpath:"$(LIBDIR)" + + +# +# Rules +# +include $(BUILDDIR)/common/Library.gmk + +vpath %.cpp $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.DEF $(CLOSED_PLATFORM_SRC)/native/sun/bridge +vpath %.rc $(CLOSED_PLATFORM_SRC)/native/sun/bridge diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk index 2c2b1774f32..86aeae9501d 100644 --- a/jdk/make/docs/CORE_PKGS.gmk +++ b/jdk/make/docs/CORE_PKGS.gmk @@ -127,6 +127,11 @@ CORE_PKGS = \ java.sql \ java.text \ java.text.spi \ + java.time \ + java.time.temporal \ + java.time.calendar \ + java.time.format \ + java.time.zone \ java.util \ java.util.concurrent \ java.util.concurrent.atomic \ diff --git a/jdk/make/docs/Makefile b/jdk/make/docs/Makefile index e181b66a4ed..c49fa8fcfcc 100644 --- a/jdk/make/docs/Makefile +++ b/jdk/make/docs/Makefile @@ -207,6 +207,7 @@ COMMON_JAVADOCFLAGS = \ -quiet \ -use \ -keywords \ + -Xdoclint:none \ $(ADDITIONAL_JAVADOCFLAGS) ifdef OPENJDK diff --git a/jdk/make/java/Makefile b/jdk/make/java/Makefile index 67f735fcb1d..80c97d27f58 100644 --- a/jdk/make/java/Makefile +++ b/jdk/make/java/Makefile @@ -39,7 +39,7 @@ SUBDIRS += version jvm redist verify fdlibm java sun_nio jli main zip # Others # Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk -SUBDIRS += security math util text net nio jar +SUBDIRS += security math util text net nio jar time SUBDIRS_desktop = awt applet beans SUBDIRS_management = management diff --git a/jdk/make/java/java/Exportedfiles.gmk b/jdk/make/java/java/Exportedfiles.gmk index f6d3c3ae1de..6b6cc3a2201 100644 --- a/jdk/make/java/java/Exportedfiles.gmk +++ b/jdk/make/java/java/Exportedfiles.gmk @@ -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 @@ -57,6 +57,7 @@ FILES_export = \ java/lang/reflect/Constructor.java \ java/lang/reflect/InvocationTargetException.java \ java/lang/reflect/Array.java \ + java/lang/reflect/Executable.java \ java/lang/reflect/Proxy.java \ java/security/AccessController.java \ java/util/Date.java \ @@ -129,6 +130,7 @@ FILES_export = \ java/lang/reflect/Constructor.java \ java/lang/reflect/InvocationTargetException.java \ java/lang/reflect/Array.java \ + java/lang/reflect/Executable.java \ java/lang/reflect/Proxy.java \ java/lang/ref/Reference.java \ java/lang/ref/Finalizer.java \ diff --git a/jdk/make/java/java/FILES_c.gmk b/jdk/make/java/java/FILES_c.gmk index aa48464771b..617780a42af 100644 --- a/jdk/make/java/java/FILES_c.gmk +++ b/jdk/make/java/java/FILES_c.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2012, 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 @@ -32,6 +32,7 @@ FILES_c = \ Compiler.c \ Console_md.c \ Double.c \ + Executable.c \ FileDescriptor_md.c \ FileInputStream.c \ FileInputStream_md.c \ diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index f6affbf987b..bf0f9833670 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -137,6 +137,7 @@ JAVA_JAVA_java = \ java/lang/Appendable.java \ java/lang/Comparable.java \ java/lang/Readable.java \ + java/lang/FunctionalInterface.java \ java/lang/Override.java \ java/lang/SafeVarargs.java \ java/lang/SuppressWarnings.java \ @@ -227,6 +228,7 @@ JAVA_JAVA_java = \ sun/util/locale/provider/LocaleResources.java \ sun/util/locale/provider/NumberFormatProviderImpl.java \ sun/util/locale/provider/RuleBasedBreakIterator.java \ + sun/util/locale/provider/ResourceBundleBasedAdapter.java \ sun/util/locale/provider/SPILocaleProviderAdapter.java \ sun/util/locale/provider/TimeZoneNameProviderImpl.java \ sun/util/locale/provider/TimeZoneNameUtility.java \ @@ -372,6 +374,11 @@ JAVA_JAVA_java = \ java/util/concurrent/atomic/AtomicReferenceArray.java \ java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java \ java/util/concurrent/atomic/AtomicStampedReference.java \ + java/util/concurrent/atomic/DoubleAccumulator.java \ + java/util/concurrent/atomic/DoubleAdder.java \ + java/util/concurrent/atomic/LongAccumulator.java \ + java/util/concurrent/atomic/LongAdder.java \ + java/util/concurrent/atomic/Striped64.java \ java/util/concurrent/locks/AbstractOwnableSynchronizer.java \ java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java \ java/util/concurrent/locks/AbstractQueuedSynchronizer.java \ diff --git a/jdk/make/java/java/mapfile-vers b/jdk/make/java/java/mapfile-vers index 97938361c99..81e678d7624 100644 --- a/jdk/make/java/java/mapfile-vers +++ b/jdk/make/java/java/mapfile-vers @@ -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 @@ -189,6 +189,7 @@ SUNWprivate_1.1 { Java_java_lang_reflect_Array_setInt; Java_java_lang_reflect_Array_setLong; Java_java_lang_reflect_Array_setShort; + Java_java_lang_reflect_Executable_getParameters0; Java_java_lang_Runtime_freeMemory; Java_java_lang_Runtime_maxMemory; Java_java_lang_Runtime_gc; diff --git a/jdk/make/java/time/Makefile b/jdk/make/java/time/Makefile new file mode 100644 index 00000000000..0ff3698bbf3 --- /dev/null +++ b/jdk/make/java/time/Makefile @@ -0,0 +1,42 @@ +# +# 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. +# + +# +# Makefile for building jar utility. +# + +BUILDDIR = ../../ +PACKAGE = java.time +include $(BUILDDIR)/common/Defs.gmk + +# +# Files +# +AUTO_FILES_JAVA_DIRS = java/time + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index 4bd2d4b84c6..a6d2ea1d0d4 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -87,6 +87,7 @@ jprt.make.rule.core.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_text}, \ ${jprt.my.test.target.set:TESTNAME=jdk_tools}, \ ${jprt.my.test.target.set:TESTNAME=jdk_jfr}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_time}, \ ${jprt.my.test.target.set:TESTNAME=jdk_other} # All vm test targets (testset=all) diff --git a/jdk/make/sun/Makefile b/jdk/make/sun/Makefile index 62392329611..3d26ee5e0b4 100644 --- a/jdk/make/sun/Makefile +++ b/jdk/make/sun/Makefile @@ -70,7 +70,7 @@ else endif # nio need to be compiled before awt to have all charsets ready -SUBDIRS = jar security javazic misc net nio text util launcher cldr +SUBDIRS = jar security javazic misc net nio text util launcher cldr tzdb ifdef BUILD_HEADLESS_ONLY DISPLAY_LIBS = awt $(HEADLESS_SUBDIR) diff --git a/jdk/make/sun/tzdb/Makefile b/jdk/make/sun/tzdb/Makefile new file mode 100644 index 00000000000..d09a1251b1d --- /dev/null +++ b/jdk/make/sun/tzdb/Makefile @@ -0,0 +1,68 @@ +# +# 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. +# + +# +# Makefile for building tzdb compiler utility. +# + +BUILDDIR = ../.. +PACKAGE = sun.tzdb +PRODUCT = sun +include $(BUILDDIR)/common/Defs.gmk + +# This program must contain a manifest that defines the execution level +# needed to follow standard Vista User Access Control Guidelines +# This must be set before Program.gmk is included +# +BUILD_MANIFEST=true + +# +# Time zone data file creation +# +TZDATA_DIR := ../javazic/tzdata +TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) +TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE)) + +TZDB_JAR = tzdb.jar + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +# +# Add to the build rule +# +build: $(LIBDIR)/$(TZDB_JAR) + +$(LIBDIR)/$(TZDB_JAR): $(TZFILES) + $(prep-target) + echo build tzdb from version $(TZDATA_VER) + $(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \ + -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE) + +clean clobber:: + $(RM) $(LIBDIR)/$(TZDB_JAR) diff --git a/jdk/make/tools/Makefile b/jdk/make/tools/Makefile index ca39dd6df67..586a1699486 100644 --- a/jdk/make/tools/Makefile +++ b/jdk/make/tools/Makefile @@ -53,6 +53,7 @@ SUBDIRS = \ makeclasslist \ strip_properties \ spp \ + tzdb \ CharsetMapping ifndef DISABLE_NIMBUS diff --git a/jdk/make/tools/src/build/tools/cldrconverter/Bundle.java b/jdk/make/tools/src/build/tools/cldrconverter/Bundle.java index 701ea4b057d..fbd95f32226 100644 --- a/jdk/make/tools/src/build/tools/cldrconverter/Bundle.java +++ b/jdk/make/tools/src/build/tools/cldrconverter/Bundle.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 @@ -274,7 +274,7 @@ class Bundle { handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns"); } - // if myMap has any empty timezone or metazone names, weed out them. + // First, weed out any empty timezone or metazone names from myMap. // Fill in any missing abbreviations if locale is "en". for (Iterator it = myMap.keySet().iterator(); it.hasNext();) { String key = it.next(); @@ -426,7 +426,7 @@ class Bundle { /* * Adjusts String[] for era names because JRE's Calendars use different - * ERA value indexes in the Buddhist and Japanese Imperial calendars. + * ERA value indexes in the Buddhist, Japanese Imperial, and Islamic calendars. */ private void adjustEraNames(Map map, CalendarType type) { String[][] eraNames = new String[ERA_KEYS.length][]; @@ -458,6 +458,11 @@ class Bundle { // Replace the value value = new String[] {"BC", value[0]}; break; + + case ISLAMIC: + // Replace the value + value = new String[] {"", value[0]}; + break; } if (!key.equals(realKey)) { map.put(realKey, value); @@ -479,6 +484,7 @@ class Bundle { for (String k : patternKeys) { if (myMap.containsKey(calendarPrefix + k)) { int len = patternKeys.length; + List rawPatterns = new ArrayList<>(); List patterns = new ArrayList<>(); for (int i = 0; i < len; i++) { String key = calendarPrefix + patternKeys[i]; @@ -487,6 +493,7 @@ class Bundle { pattern = (String) parentsMap.remove(key); } if (pattern != null) { + rawPatterns.add(i, pattern); patterns.add(i, translateDateFormatLetters(calendarType, pattern)); } } @@ -494,6 +501,9 @@ class Bundle { return; } String key = calendarPrefix + name; + if (!rawPatterns.equals(patterns)) { + myMap.put("cldr." + key, rawPatterns.toArray(new String[len])); + } myMap.put(key, patterns.toArray(new String[len])); break; } diff --git a/jdk/make/tools/src/build/tools/cldrconverter/CLDRConverter.java b/jdk/make/tools/src/build/tools/cldrconverter/CLDRConverter.java index 1d5cd5e2d8f..069afb84d1f 100644 --- a/jdk/make/tools/src/build/tools/cldrconverter/CLDRConverter.java +++ b/jdk/make/tools/src/build/tools/cldrconverter/CLDRConverter.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 @@ -58,6 +58,7 @@ public class CLDRConverter { static final String LOCALE_NAME_PREFIX = "locale.displayname."; static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol."; static final String CURRENCY_NAME_PREFIX = "currency.displayname."; + static final String CALENDAR_NAME_PREFIX = "calendarname."; static final String TIMEZONE_ID_PREFIX = "timezone.id."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; @@ -519,35 +520,70 @@ public class CLDRConverter { return calendarData; } + static final String[] FORMAT_DATA_ELEMENTS = { + "MonthNames", + "standalone.MonthNames", + "MonthAbbreviations", + "standalone.MonthAbbreviations", + "MonthNarrow", + "standalone.MonthNarrows", + "DayNames", + "standalone.DayNames", + "DayAbbreviations", + "standalone.DayAbbreviations", + "DayNarrows", + "standalone.DayNarrows", + "AmPmMarkers", + "narrow.AmPmMarkers", + "long.Eras", + "Eras", + "narrow.Eras", + "field.era", + "field.year", + "field.month", + "field.week", + "field.weekday", + "field.dayperiod", + "field.hour", + "field.minute", + "field.second", + "field.zone", + "TimePatterns", + "DatePatterns", + "DateTimePatterns", + "DateTimePatternChars" + }; + private static Map extractFormatData(Map map, String id) { Map formatData = new LinkedHashMap<>(); for (CalendarType calendarType : CalendarType.values()) { String prefix = calendarType.keyElementName(); - copyIfPresent(map, prefix + "MonthNames", formatData); // default FORMAT since JDK8 - copyIfPresent(map, prefix + "standalone.MonthNames", formatData); - copyIfPresent(map, prefix + "MonthAbbreviations", formatData); - copyIfPresent(map, prefix + "standalone.MonthAbbreviations", formatData); - copyIfPresent(map, prefix + "MonthNarrow", formatData); - copyIfPresent(map, prefix + "standalone.MonthNarrows", formatData); - copyIfPresent(map, prefix + "DayNames", formatData); - copyIfPresent(map, prefix + "standalone.DayNames", formatData); - copyIfPresent(map, prefix + "DayAbbreviations", formatData); - copyIfPresent(map, prefix + "standalone.DayAbbreviations", formatData); - copyIfPresent(map, prefix + "DayNarrows", formatData); - copyIfPresent(map, prefix + "standalone.DayNarrows", formatData); - copyIfPresent(map, prefix + "AmPmMarkers", formatData); - copyIfPresent(map, prefix + "narrow.AmPmMarkers", formatData); - copyIfPresent(map, prefix + "long.Eras", formatData); - copyIfPresent(map, prefix + "Eras", formatData); - copyIfPresent(map, prefix + "narrow.Eras", formatData); - copyIfPresent(map, prefix + "TimePatterns", formatData); - copyIfPresent(map, prefix + "DatePatterns", formatData); - copyIfPresent(map, prefix + "DateTimePatterns", formatData); - copyIfPresent(map, prefix + "DateTimePatternChars", formatData); + for (String element : FORMAT_DATA_ELEMENTS) { + String key = prefix + element; + copyIfPresent(map, "cldr." + key, formatData); + copyIfPresent(map, key, formatData); + } + } + + // Copy available calendar names + for (String key : map.keySet()) { + if (key.startsWith(CLDRConverter.CALENDAR_NAME_PREFIX)) { + String type = key.substring(CLDRConverter.CALENDAR_NAME_PREFIX.length()); + for (CalendarType calendarType : CalendarType.values()) { + if (type.equals(calendarType.lname())) { + Object value = map.get(key); + formatData.put(key, value); + String ukey = CLDRConverter.CALENDAR_NAME_PREFIX + calendarType.uname(); + if (!key.equals(ukey)) { + formatData.put(ukey, value); + } + } + } + } } copyIfPresent(map, "DefaultNumberingSystem", formatData); - String defaultScript = (String) map.get("DefaultNumberingSystem"); + @SuppressWarnings("unchecked") List numberingScripts = (List) map.remove("numberingScripts"); if (numberingScripts != null) { diff --git a/jdk/make/tools/src/build/tools/cldrconverter/CalendarType.java b/jdk/make/tools/src/build/tools/cldrconverter/CalendarType.java index 0a0e0637c57..b530080ae71 100644 --- a/jdk/make/tools/src/build/tools/cldrconverter/CalendarType.java +++ b/jdk/make/tools/src/build/tools/cldrconverter/CalendarType.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 @@ -31,26 +31,42 @@ import java.util.Locale; * Constants for the Calendars supported by JRE. */ enum CalendarType { - - GREGORIAN, BUDDHIST, JAPANESE; + GREGORIAN("gregory"), BUDDHIST, JAPANESE, ROC, ISLAMIC, ISLAMIC_CIVIL("islamicc"); private static final int[][] ERA_DATA = { // start index, array length {0, 2}, // gregorian {0, 1}, // buddhist {232, 4}, // japanese (eras from Meiji) + {0, 2}, // roc (Minguo) + {0, 1}, // islamic (Hijrah) + {0, 1}, // islamicc (same as islamic) }; private final String lname; // lowercase name + private final String uname; // unicode key name (e.g., "gregory" for GREGORIAN) private CalendarType() { - lname = name().toLowerCase(Locale.ROOT); + this(null); + } + + private CalendarType(String uname) { + String lname = name().toLowerCase(Locale.ROOT); + if (lname.equals("islamic_civil")) { + lname = "islamic-civil"; + } + this.lname = lname; + this.uname = (uname != null) ? uname : lname; } String lname() { return lname; } + String uname() { + return uname; + } + String keyElementName() { return (this == GREGORIAN) ? "" : lname + "."; } diff --git a/jdk/make/tools/src/build/tools/cldrconverter/LDMLParseHandler.java b/jdk/make/tools/src/build/tools/cldrconverter/LDMLParseHandler.java index 812aab244fa..695312408f8 100644 --- a/jdk/make/tools/src/build/tools/cldrconverter/LDMLParseHandler.java +++ b/jdk/make/tools/src/build/tools/cldrconverter/LDMLParseHandler.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 @@ -71,6 +71,13 @@ class LDMLParseHandler extends AbstractLDMLHandler { // ignore this element - it has language and territory elements that aren't locale data pushIgnoredContainer(qName); break; + case "type": + if ("calendar".equals(attributes.getValue("key"))) { + pushStringEntry(qName, attributes, CLDRConverter.CALENDAR_NAME_PREFIX + attributes.getValue("type")); + } else { + pushIgnoredContainer(qName); + } + break; case "language": // for LocaleNames // copy string @@ -98,19 +105,30 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "symbol": // for CurrencyNames // need to get the key from the containing element - pushStringEntry(qName, attributes, CLDRConverter.CURRENCY_SYMBOL_PREFIX + getContainerKey()); + pushStringEntry(qName, attributes, CLDRConverter.CURRENCY_SYMBOL_PREFIX + + getContainerKey()); break; + + // Calendar or currency case "displayName": - // for CurrencyNames - // need to get the key from the containing element - // ignore if is has "count" attribute - String containerKey = getContainerKey(); - if (containerKey != null && attributes.getValue("count") == null) { - pushStringEntry(qName, attributes, - CLDRConverter.CURRENCY_NAME_PREFIX + containerKey.toLowerCase(Locale.ROOT), - attributes.getValue("type")); - } else { - pushIgnoredContainer(qName); + { + if (currentCalendarType != null) { + pushStringEntry(qName, attributes, + currentCalendarType.keyElementName() + "field." + getContainerKey()); + } else { + // for CurrencyNames + // need to get the key from the containing element + // ignore if is has "count" attribute + String containerKey = getContainerKey(); + if (containerKey != null && attributes.getValue("count") == null) { + pushStringEntry(qName, attributes, + CLDRConverter.CURRENCY_NAME_PREFIX + + containerKey.toLowerCase(Locale.ROOT), + attributes.getValue("type")); + } else { + pushIgnoredContainer(qName); + } + } } break; @@ -130,6 +148,35 @@ class LDMLParseHandler extends AbstractLDMLHandler { } } break; + case "fields": + if (currentCalendarType != null) { + pushContainer(qName, attributes); + } else { + pushIgnoredContainer(qName); + } + break; + case "field": + { + String type = attributes.getValue("type"); + switch (type) { + case "era": + case "year": + case "month": + case "week": + case "weekday": + case "dayperiod": + case "hour": + case "minute": + case "second": + case "zone": + pushKeyContainer(qName, attributes, type); + break; + default: + pushIgnoredContainer(qName); + break; + } + } + break; case "monthContext": { // for FormatData diff --git a/jdk/make/tools/src/build/tools/tzdb/ChronoField.java b/jdk/make/tools/src/build/tools/tzdb/ChronoField.java new file mode 100644 index 00000000000..7ce34bbfae2 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ChronoField.java @@ -0,0 +1,180 @@ +/* + * 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) 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 build.tools.tzdb; + +/** + * A standard set of date/time fields. + * + * @since 1.8 + */ +enum ChronoField { + + /** + * The second-of-minute. + *

+ * This counts the second within the minute, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_MINUTE("SecondOfMinute", 0, 59), + + /** + * The second-of-day. + *

+ * This counts the second within the day, from 0 to (24 * 60 * 60) - 1. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_DAY("SecondOfDay", 0, 86400 - 1), + + /** + * The minute-of-hour. + *

+ * This counts the minute within the hour, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + MINUTE_OF_HOUR("MinuteOfHour", 0, 59), + + /** + * The hour-of-day. + *

+ * This counts the hour within the day, from 0 to 23. + * This is the hour that would be observed on a standard 24-hour digital clock. + * This field has the same meaning for all calendar systems. + */ + HOUR_OF_DAY("HourOfDay", 0, 23), + + + /** + * The day-of-month. + *

+ * This represents the concept of the day within the month. + * In the default ISO calendar system, this has values from 1 to 31 in most months. + * April, June, September, November have days from 1 to 30, while February has days + * from 1 to 28, or 29 in a leap year. + *

+ * Non-ISO calendar systems should implement this field using the most recognized + * day-of-month values for users of the calendar system. + * Normally, this is a count of days from 1 to the length of the month. + */ + DAY_OF_MONTH("DayOfMonth", 1, 31), + + /** + * The month-of-year, such as March. + *

+ * This represents the concept of the month within the year. + * In the default ISO calendar system, this has values from January (1) to December (12). + *

+ * Non-ISO calendar systems should implement this field using the most recognized + * month-of-year values for users of the calendar system. + * Normally, this is a count of months starting from 1. + */ + MONTH_OF_YEAR("MonthOfYear", 1, 12), + + /** + * The proleptic year, such as 2012. + *

+ * This represents the concept of the year, counting sequentially and using negative numbers. + * The proleptic year is not interpreted in terms of the era. + * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era. + *

+ * The standard mental model for a date is based on three concepts - year, month and day. + * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Note that there is no reference to eras. + * The full model for a date requires four concepts - era, year, month and day. These map onto + * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used. + * See {@link ChronoLocalDate} for more discussion on this topic. + *

+ * Non-ISO calendar systems should implement this field as follows. + * If the calendar system has only two eras, before and after a fixed date, then the + * proleptic-year value must be the same as the year-of-era value for the later era, + * and increasingly negative for the earlier era. + * If the calendar system has more than two eras, then the proleptic-year value may be + * defined with any appropriate value, although defining it to be the same as ISO may be + * the best option. + */ + YEAR("Year", -999_999_999, 999_999_999); + + private final String name; + private final int min; + private final int max; + + private ChronoField(String name, int min, int max) { + this.name = name; + this.min= min; + this.max= max; + } + + /** + * Checks that the specified value is valid for this field. + *

+ * + * @param value the value to check + * @return the value that was passed in + */ + public int checkValidValue(int value) { + if (value >= min && value <= max) { + return value; + } + throw new DateTimeException("Invalid value for " + name + " value: " + value); + } + + public String toString() { + return name; + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/DateTimeException.java b/jdk/make/tools/src/build/tools/tzdb/DateTimeException.java new file mode 100644 index 00000000000..2b7674df3ff --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/DateTimeException.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +/* + * 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 build.tools.tzdb; + +/** + * Exception used to indicate a problem while calculating a date-time. + *

+ * This exception is used to indicate problems with creating, querying + * and manipulating date-time objects. + * + * @since 1.8 + */ +class DateTimeException extends RuntimeException { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -1632418723876261839L; + + /** + * Constructs a new date-time exception with the specified message. + * + * @param message the message to use for this exception, may be null + */ + public DateTimeException(String message) { + super(message); + } + + /** + * Constructs a new date-time exception with the specified message and cause. + * + * @param message the message to use for this exception, may be null + * @param cause the cause of the exception, may be null + */ + public DateTimeException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/LocalDate.java b/jdk/make/tools/src/build/tools/tzdb/LocalDate.java new file mode 100644 index 00000000000..fedab6d3156 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/LocalDate.java @@ -0,0 +1,363 @@ +/* + * 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. + */ + +/* + * 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) 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 build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; +import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY; +import static build.tools.tzdb.ChronoField.DAY_OF_MONTH; +import static build.tools.tzdb.ChronoField.MONTH_OF_YEAR; +import static build.tools.tzdb.ChronoField.YEAR; + +import java.util.Objects; + +/** + * A date without a time-zone in the ISO-8601 calendar system, + * such as {@code 2007-12-03}. + * + * @since 1.8 + */ +final class LocalDate { + + /** + * The minimum supported {@code LocalDate}, '-999999999-01-01'. + * This could be used by an application as a "far past" date. + */ + public static final LocalDate MIN = new LocalDate(YEAR_MIN_VALUE, 1, 1); + /** + * The maximum supported {@code LocalDate}, '+999999999-12-31'. + * This could be used by an application as a "far future" date. + */ + public static final LocalDate MAX = new LocalDate(YEAR_MAX_VALUE, 12, 31); + + /** + * The number of days in a 400 year cycle. + */ + private static final int DAYS_PER_CYCLE = 146097; + /** + * The number of days from year zero to year 1970. + * There are five 400 year cycles from year zero to 2000. + * There are 7 leap years from 1970 to 2000. + */ + static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L); + + /** + * The year. + */ + private final int year; + /** + * The month-of-year. + */ + private final short month; + /** + * The day-of-month. + */ + private final short day; + + /** + * Obtains an instance of {@code LocalDate} from a year, month and day. + *

+ * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the local date, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public static LocalDate of(int year, int month, int dayOfMonth) { + YEAR.checkValidValue(year); + MONTH_OF_YEAR.checkValidValue(month); + DAY_OF_MONTH.checkValidValue(dayOfMonth); + if (dayOfMonth > 28 && dayOfMonth > lengthOfMonth(month, isLeapYear(year))) { + if (dayOfMonth == 29) { + throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year"); + } else { + throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "'"); + } + } + return new LocalDate(year, month, dayOfMonth); + } + + /** + * Constructor, previously validated. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, not null + * @param dayOfMonth the day-of-month to represent, valid for year-month, from 1 to 31 + */ + private LocalDate(int year, int month, int dayOfMonth) { + this.year = year; + this.month = (short) month; + this.day = (short) dayOfMonth; + } + + /** + * Gets the year field. + *

+ * This method returns the primitive {@code int} value for the year. + *

+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return year; + } + + /** + * Gets the month-of-year field as an int from 1 to 12. + * + * @return the month-of-year + */ + public int getMonth() { + return month; + } + + /** + * Gets the day-of-month field. + *

+ * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return day; + } + + /** + * Gets the day-of-week field, which is an int from 1 to 7. + * + * @return the day-of-week + */ + public int getDayOfWeek() { + return (int)floorMod(toEpochDay() + 3, 7) + 1; + } + + /** + * Returns a copy of this {@code LocalDate} with the specified number of days added. + *

+ * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

+ * For example, 2008-12-31 plus one day would result in 2009-01-01. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param daysToAdd the days to add, may be negative + * @return a {@code LocalDate} based on this date with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDate plusDays(long daysToAdd) { + if (daysToAdd == 0) { + return this; + } + long mjDay = addExact(toEpochDay(), daysToAdd); + return LocalDate.ofEpochDay(mjDay); + } + + /** + * Returns a copy of this {@code LocalDate} with the specified number of days subtracted. + *

+ * This method subtracts the specified amount from the days field decrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

+ * For example, 2009-01-01 minus one day would result in 2008-12-31. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param daysToSubtract the days to subtract, may be negative + * @return a {@code LocalDate} based on this date with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDate minusDays(long daysToSubtract) { + return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); + } + + /** + * Obtains an instance of {@code LocalDate} from the epoch day count. + *

+ * The Epoch Day count is a simple incrementing count of days + * where day 0 is 1970-01-01. Negative numbers represent earlier days. + * + * @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01 + * @return the local date, not null + * @throws DateTimeException if the epoch days exceeds the supported date range + */ + public static LocalDate ofEpochDay(long epochDay) { + long zeroDay = epochDay + DAYS_0000_TO_1970; + // find the march-based year + zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle + long adjust = 0; + if (zeroDay < 0) { + // adjust negative years to positive for calculation + long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1; + adjust = adjustCycles * 400; + zeroDay += -adjustCycles * DAYS_PER_CYCLE; + } + long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE; + long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); + if (doyEst < 0) { + // fix estimate + yearEst--; + doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); + } + yearEst += adjust; // reset any negative year + int marchDoy0 = (int) doyEst; + + // convert march-based values back to january-based + int marchMonth0 = (marchDoy0 * 5 + 2) / 153; + int month = (marchMonth0 + 2) % 12 + 1; + int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1; + yearEst += marchMonth0 / 10; + + // check year now we are certain it is correct + int year = YEAR.checkValidValue((int)yearEst); + return new LocalDate(year, month, dom); + } + + public long toEpochDay() { + long y = year; + long m = month; + long total = 0; + total += 365 * y; + if (y >= 0) { + total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400; + } else { + total -= y / -4 - y / -100 + y / -400; + } + total += ((367 * m - 362) / 12); + total += day - 1; + if (m > 2) { + total--; + if (isLeapYear(year) == false) { + total--; + } + } + return total - DAYS_0000_TO_1970; + } + + /** + * Compares this date to another date. + *

+ * The comparison is primarily based on the date, from earliest to latest. + * It is "consistent with equals", as defined by {@link Comparable}. + *

+ * If all the dates being compared are instances of {@code LocalDate}, + * then the comparison will be entirely based on the date. + * If some dates being compared are in different chronologies, then the + * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(LocalDate otherDate) { + int cmp = (year - otherDate.year); + if (cmp == 0) { + cmp = (month - otherDate.month); + if (cmp == 0) { + cmp = (day - otherDate.day); + } + } + return cmp; + } + + /** + * Checks if this date is equal to another date. + *

+ * Compares this {@code LocalDate} with another ensuring that the date is the same. + *

+ * Only objects of type {@code LocalDate} are compared, other types return false. + * To compare the dates of two {@code TemporalAccessor} instances, including dates + * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalDate) { + return compareTo((LocalDate) obj) == 0; + } + return false; + } + + /** + * A hash code for this date. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + int yearValue = year; + int monthValue = month; + int dayValue = day; + return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue)); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/LocalDateTime.java b/jdk/make/tools/src/build/tools/tzdb/LocalDateTime.java new file mode 100644 index 00000000000..ced37b72613 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/LocalDateTime.java @@ -0,0 +1,427 @@ +/* + * 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. + */ + +/* + * 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) 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 build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; +import static build.tools.tzdb.LocalTime.HOURS_PER_DAY; +import static build.tools.tzdb.LocalTime.MICROS_PER_DAY; +import static build.tools.tzdb.LocalTime.MILLIS_PER_DAY; +import static build.tools.tzdb.LocalTime.MINUTES_PER_DAY; +import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY; +import static build.tools.tzdb.LocalTime.SECONDS_PER_MINUTE; +import static build.tools.tzdb.LocalTime.SECONDS_PER_HOUR; + +import java.util.Objects; + +/** + * A date-time without a time-zone in the ISO-8601 calendar system, + * such as {@code 2007-12-03T10:15:30}. + * + * @since 1.8 + */ +final class LocalDateTime { + + /** + * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'. + * This is the local date-time of midnight at the start of the minimum date. + * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}. + * This could be used by an application as a "far past" date-time. + */ + public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN); + /** + * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'. + * This is the local date-time just before midnight at the end of the maximum date. + * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}. + * This could be used by an application as a "far future" date-time. + */ + public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX); + + /** + * The date part. + */ + private final LocalDate date; + /** + * The time part. + */ + private final LocalTime time; + + /** + * Obtains an instance of {@code LocalDateTime} from year, month, + * day, hour and minute, setting the second and nanosecond to zero. + *

+ * The day must be valid for the year and month, otherwise an exception will be thrown. + * The second and nanosecond fields will be set to zero. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @return the local date-time, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) { + LocalDate date = LocalDate.of(year, month, dayOfMonth); + LocalTime time = LocalTime.of(hour, minute); + return new LocalDateTime(date, time); + } + + /** + * Obtains an instance of {@code LocalDateTime} from a date and time. + * + * @param date the local date, not null + * @param time the local time, not null + * @return the local date-time, not null + */ + public static LocalDateTime of(LocalDate date, LocalTime time) { + Objects.requireNonNull(date, "date"); + Objects.requireNonNull(time, "time"); + return new LocalDateTime(date, time); + } + + /** + * Obtains an instance of {@code LocalDateTime} using seconds from the + * epoch of 1970-01-01T00:00:00Z. + *

+ * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field + * to be converted to a local date-time. This is primarily intended for + * low-level conversions rather than general application usage. + * + * @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z + * @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999 + * @param offset the zone offset, not null + * @return the local date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + long localSecond = epochSecond + offset.getTotalSeconds(); // overflow caught later + long localEpochDay = floorDiv(localSecond, SECONDS_PER_DAY); + int secsOfDay = (int)floorMod(localSecond, SECONDS_PER_DAY); + LocalDate date = LocalDate.ofEpochDay(localEpochDay); + LocalTime time = LocalTime.ofSecondOfDay(secsOfDay); // ignore nano + return new LocalDateTime(date, time); + } + + /** + * Constructor. + * + * @param date the date part of the date-time, validated not null + * @param time the time part of the date-time, validated not null + */ + private LocalDateTime(LocalDate date, LocalTime time) { + this.date = date; + this.time = time; + } + + /** + * Returns a copy of this date-time with the new date and time, checking + * to see if a new object is in fact required. + * + * @param newDate the date of the new date-time, not null + * @param newTime the time of the new date-time, not null + * @return the date-time, not null + */ + private LocalDateTime with(LocalDate newDate, LocalTime newTime) { + if (date == newDate && time == newTime) { + return this; + } + return new LocalDateTime(newDate, newTime); + } + + /** + * Gets the {@code LocalDate} part of this date-time. + *

+ * This returns a {@code LocalDate} with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public LocalDate getDate() { + return date; + } + + /** + * Gets the year field. + *

+ * This method returns the primitive {@code int} value for the year. + *

+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return date.getYear(); + } + + /** + * Gets the month-of-year field as an int from 1 to 12. + * + * @return the month-of-year + */ + public int getMonth() { + return date.getMonth(); + } + + /** + * Gets the day-of-month field. + *

+ * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return date.getDayOfMonth(); + } + + /** + * Gets the day-of-week field, which is an integer from 1 to 7. + * + * @return the day-of-week, from 1 to 7 + */ + public int getDayOfWeek() { + return date.getDayOfWeek(); + } + + /** + * Gets the {@code LocalTime} part of this date-time. + *

+ * This returns a {@code LocalTime} with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public LocalTime getTime() { + return time; + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return time.getHour(); + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return time.getMinute(); + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return time.getSecond(); + } + + /** + * Converts this date-time to the number of seconds from the epoch + * of 1970-01-01T00:00:00Z. + *

+ * This combines this local date-time and the specified offset to calculate the + * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier are negative. + *

+ * This default implementation calculates from the epoch-day of the date and the + * second-of-day of the time. + * + * @param offset the offset to use for the conversion, not null + * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z + */ + public long toEpochSecond(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + long epochDay = getDate().toEpochDay(); + long secs = epochDay * 86400 + getTime().toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period in days added. + *

+ * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

+ * For example, 2008-12-31 plus one day would result in 2009-01-01. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return a {@code LocalDateTime} based on this date-time with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDateTime plusDays(long days) { + LocalDate newDate = date.plusDays(days); + return with(newDate, time); + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to add, may be negative + * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDateTime plusSeconds(long seconds) { + return plusWithOverflow(date, 0, 0, seconds, 1); + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period added. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param newDate the new date to base the calculation on, not null + * @param hours the hours to add, may be negative + * @param minutes the minutes to add, may be negative + * @param seconds the seconds to add, may be negative + * @param nanos the nanos to add, may be negative + * @param sign the sign to determine add or subtract + * @return the combined result, not null + */ + private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, int sign) { + if ((hours | minutes | seconds) == 0) { + return with(newDate, time); + } + long totDays = seconds / SECONDS_PER_DAY + // max/24*60*60 + minutes / MINUTES_PER_DAY + // max/24*60 + hours / HOURS_PER_DAY; // max/24 + totDays *= sign; // total max*0.4237... + long totSecs = (seconds % SECONDS_PER_DAY) + + (minutes % MINUTES_PER_DAY) * SECONDS_PER_MINUTE + + (hours % HOURS_PER_DAY) * SECONDS_PER_HOUR; + long curSoD = time.toSecondOfDay(); + totSecs = totSecs * sign + curSoD; // total 432000000000000 + totDays += floorDiv(totSecs, SECONDS_PER_DAY); + + int newSoD = (int)floorMod(totSecs, SECONDS_PER_DAY); + LocalTime newTime = (newSoD == curSoD ? time : LocalTime.ofSecondOfDay(newSoD)); + return with(newDate.plusDays(totDays), newTime); + } + + /** + * Compares this date-time to another date-time. + *

+ * The comparison is primarily based on the date-time, from earliest to latest. + * It is "consistent with equals", as defined by {@link Comparable}. + *

+ * If all the date-times being compared are instances of {@code LocalDateTime}, + * then the comparison will be entirely based on the date-time. + * If some dates being compared are in different chronologies, then the + * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}. + * + * @param other the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(LocalDateTime other) { + int cmp = date.compareTo(other.getDate()); + if (cmp == 0) { + cmp = time.compareTo(other.getTime()); + } + return cmp; + } + + /** + * Checks if this date-time is equal to another date-time. + *

+ * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same. + * Only objects of type {@code LocalDateTime} are compared, other types return false. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date-time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalDateTime) { + LocalDateTime other = (LocalDateTime) obj; + return date.equals(other.date) && time.equals(other.time); + } + return false; + } + + /** + * A hash code for this date-time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return date.hashCode() ^ time.hashCode(); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/LocalTime.java b/jdk/make/tools/src/build/tools/tzdb/LocalTime.java new file mode 100644 index 00000000000..0fc31868944 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/LocalTime.java @@ -0,0 +1,388 @@ +/* + * 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. + */ + +/* + * 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) 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 build.tools.tzdb; + +import static build.tools.tzdb.ChronoField.HOUR_OF_DAY; +import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR; +import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE; +import static build.tools.tzdb.ChronoField.SECOND_OF_DAY; + +import java.util.Objects; + +/** + * A time without time-zone in the ISO-8601 calendar system, + * such as {@code 10:15:30}. + * + */ +final class LocalTime { + + /** + * The minimum supported {@code LocalTime}, '00:00'. + * This is the time of midnight at the start of the day. + */ + public static final LocalTime MIN; + /** + * The minimum supported {@code LocalTime}, '23:59:59.999999999'. + * This is the time just before midnight at the end of the day. + */ + public static final LocalTime MAX; + /** + * The time of midnight at the start of the day, '00:00'. + */ + public static final LocalTime MIDNIGHT; + /** + * The time of noon in the middle of the day, '12:00'. + */ + public static final LocalTime NOON; + /** + * Constants for the local time of each hour. + */ + private static final LocalTime[] HOURS = new LocalTime[24]; + static { + for (int i = 0; i < HOURS.length; i++) { + HOURS[i] = new LocalTime(i, 0, 0); + } + MIDNIGHT = HOURS[0]; + NOON = HOURS[12]; + MIN = HOURS[0]; + MAX = new LocalTime(23, 59, 59); + } + + /** + * Hours per day. + */ + static final int HOURS_PER_DAY = 24; + /** + * Minutes per hour. + */ + static final int MINUTES_PER_HOUR = 60; + /** + * Minutes per day. + */ + static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; + /** + * Seconds per minute. + */ + static final int SECONDS_PER_MINUTE = 60; + /** + * Seconds per hour. + */ + static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + /** + * Seconds per day. + */ + static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; + /** + * Milliseconds per day. + */ + static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L; + /** + * Microseconds per day. + */ + static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L; + + /** + * The hour. + */ + private final byte hour; + /** + * The minute. + */ + private final byte minute; + /** + * The second. + */ + private final byte second; + + /** + * Obtains an instance of {@code LocalTime} from an hour and minute. + *

+ * The second and nanosecond fields will be set to zero by this factory method. + *

+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @return the local time, not null + * @throws DateTimeException if the value of any field is out of range + */ + public static LocalTime of(int hour, int minute) { + HOUR_OF_DAY.checkValidValue(hour); + if (minute == 0) { + return HOURS[hour]; // for performance + } + MINUTE_OF_HOUR.checkValidValue(minute); + return new LocalTime(hour, minute, 0); + } + + /** + * Obtains an instance of {@code LocalTime} from an hour, minute and second. + *

+ * The nanosecond field will be set to zero by this factory method. + *

+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @param second the second-of-minute to represent, from 0 to 59 + * @return the local time, not null + * @throws DateTimeException if the value of any field is out of range + */ + public static LocalTime of(int hour, int minute, int second) { + HOUR_OF_DAY.checkValidValue(hour); + if ((minute | second) == 0) { + return HOURS[hour]; // for performance + } + MINUTE_OF_HOUR.checkValidValue(minute); + SECOND_OF_MINUTE.checkValidValue(second); + return new LocalTime(hour, minute, second); + } + + /** + * Obtains an instance of {@code LocalTime} from a second-of-day value. + *

+ * This factory may return a cached value, but applications must not rely on this. + * + * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1} + * @return the local time, not null + * @throws DateTimeException if the second-of-day value is invalid + */ + public static LocalTime ofSecondOfDay(int secondOfDay) { + SECOND_OF_DAY.checkValidValue(secondOfDay); + int hours = secondOfDay / SECONDS_PER_HOUR; + secondOfDay -= hours * SECONDS_PER_HOUR; + int minutes = secondOfDay / SECONDS_PER_MINUTE; + secondOfDay -= minutes * SECONDS_PER_MINUTE; + return create(hours, minutes, secondOfDay); + } + + + /** + * Creates a local time from the hour, minute, second and nanosecond fields. + *

+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, validated from 0 to 23 + * @param minute the minute-of-hour to represent, validated from 0 to 59 + * @param second the second-of-minute to represent, validated from 0 to 59 + * @return the local time, not null + */ + private static LocalTime create(int hour, int minute, int second) { + if ((minute | second) == 0) { + return HOURS[hour]; + } + return new LocalTime(hour, minute, second); + } + + /** + * Constructor, previously validated. + * + * @param hour the hour-of-day to represent, validated from 0 to 23 + * @param minute the minute-of-hour to represent, validated from 0 to 59 + * @param second the second-of-minute to represent, validated from 0 to 59 + */ + private LocalTime(int hour, int minute, int second) { + this.hour = (byte) hour; + this.minute = (byte) minute; + this.second = (byte) second; + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return hour; + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return minute; + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return second; + } + + /** + * Returns a copy of this {@code LocalTime} with the specified period in seconds added. + *

+ * This adds the specified number of seconds to this time, returning a new time. + * The calculation wraps around midnight. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param secondstoAdd the seconds to add, may be negative + * @return a {@code LocalTime} based on this time with the seconds added, not null + */ + public LocalTime plusSeconds(long secondstoAdd) { + if (secondstoAdd == 0) { + return this; + } + int sofd = hour * SECONDS_PER_HOUR + + minute * SECONDS_PER_MINUTE + second; + int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY; + if (sofd == newSofd) { + return this; + } + int newHour = newSofd / SECONDS_PER_HOUR; + int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; + int newSecond = newSofd % SECONDS_PER_MINUTE; + return create(newHour, newMinute, newSecond); + } + + /** + * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted. + *

+ * This subtracts the specified number of seconds from this time, returning a new time. + * The calculation wraps around midnight. + *

+ * This instance is immutable and unaffected by this method call. + * + * @param secondsToSubtract the seconds to subtract, may be negative + * @return a {@code LocalTime} based on this time with the seconds subtracted, not null + */ + public LocalTime minusSeconds(long secondsToSubtract) { + return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY)); + } + + /** + * Extracts the time as seconds of day, + * from {@code 0} to {@code 24 * 60 * 60 - 1}. + * + * @return the second-of-day equivalent to this time + */ + public int toSecondOfDay() { + int total = hour * SECONDS_PER_HOUR; + total += minute * SECONDS_PER_MINUTE; + total += second; + return total; + } + + /** + * Compares this {@code LocalTime} to another time. + *

+ * The comparison is based on the time-line position of the local times within a day. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other time to compare to, not null + * @return the comparator value, negative if less, positive if greater + * @throws NullPointerException if {@code other} is null + */ + public int compareTo(LocalTime other) { + int cmp = Integer.compare(hour, other.hour); + if (cmp == 0) { + cmp = Integer.compare(minute, other.minute); + if (cmp == 0) { + cmp = Integer.compare(second, other.second); + } + } + return cmp; + } + + /** + * Checks if this time is equal to another time. + *

+ * The comparison is based on the time-line position of the time within a day. + *

+ * Only objects of type {@code LocalTime} are compared, other types return false. + * To compare the date of two {@code TemporalAccessor} instances, use + * {@link ChronoField#NANO_OF_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalTime) { + LocalTime other = (LocalTime) obj; + return hour == other.hour && minute == other.minute && + second == other.second; + } + return false; + } + + /** + * A hash code for this time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + long sod = toSecondOfDay(); + return (int) (sod ^ (sod >>> 32)); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/TimeDefinition.java b/jdk/make/tools/src/build/tools/tzdb/TimeDefinition.java new file mode 100644 index 00000000000..8a5853db3d7 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/TimeDefinition.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +/* + * 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 build.tools.tzdb; + +import java.util.Objects; + +/** + * A definition of the way a local time can be converted to the actual + * transition date-time. + *

+ * Time zone rules are expressed in one of three ways: + *

    + *
  • Relative to UTC
  • + *
  • Relative to the standard offset in force
  • + *
  • Relative to the wall offset (what you would see on a clock on the wall)
  • + *

+ */ +public enum TimeDefinition { + /** The local date-time is expressed in terms of the UTC offset. */ + UTC, + /** The local date-time is expressed in terms of the wall offset. */ + WALL, + /** The local date-time is expressed in terms of the standard offset. */ + STANDARD; + + /** + * Converts the specified local date-time to the local date-time actually + * seen on a wall clock. + *

+ * This method converts using the type of this enum. + * The output is defined relative to the 'before' offset of the transition. + *

+ * The UTC type uses the UTC offset. + * The STANDARD type uses the standard offset. + * The WALL type returns the input date-time. + * The result is intended for use with the wall-offset. + * + * @param dateTime the local date-time, not null + * @param standardOffset the standard offset, not null + * @param wallOffset the wall offset, not null + * @return the date-time relative to the wall/before offset, not null + */ + public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) { + switch (this) { + case UTC: { + int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds(); + return dateTime.plusSeconds(difference); + } + case STANDARD: { + int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds(); + return dateTime.plusSeconds(difference); + } + default: // WALL + return dateTime; + } + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java new file mode 100644 index 00000000000..7b32ccf267a --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java @@ -0,0 +1,876 @@ +/* + * 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) 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 build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +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; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A builder that can read the TZDB time-zone files and build {@code ZoneRules} instances. + * + * @since 1.8 + */ +public final class TzdbZoneRulesCompiler { + + private static final Matcher YEAR = Pattern.compile("(?i)(?min)|(?max)|(?only)|(?[0-9]+)").matcher(""); + private static final Matcher MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)").matcher(""); + private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher(""); + private static final Matcher TIME = Pattern.compile("(?-)?+(?[0-9]{1,2})(:(?[0-5][0-9]))?+(:(?[0-5][0-9]))?+").matcher(""); + + /** + * Constant for MJD 1972-01-01. + */ + private static final long MJD_1972_01_01 = 41317L; + + /** + * Reads a set of TZDB files and builds a single combined data file. + * + * @param args the arguments + */ + public static void main(String[] args) { + if (args.length < 2) { + outputHelp(); + return; + } + + // parse args + String version = null; + File baseSrcDir = null; + File dstDir = null; + boolean verbose = false; + + // parse options + int i; + for (i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.startsWith("-") == false) { + break; + } + if ("-srcdir".equals(arg)) { + if (baseSrcDir == null && ++i < args.length) { + baseSrcDir = new File(args[i]); + continue; + } + } else if ("-dstdir".equals(arg)) { + if (dstDir == null && ++i < args.length) { + dstDir = new File(args[i]); + continue; + } + } else if ("-version".equals(arg)) { + if (version == null && ++i < args.length) { + version = args[i]; + continue; + } + } else if ("-verbose".equals(arg)) { + if (verbose == false) { + verbose = true; + continue; + } + } else if ("-help".equals(arg) == false) { + System.out.println("Unrecognised option: " + arg); + } + outputHelp(); + return; + } + + // check source directory + if (baseSrcDir == null) { + System.out.println("Source directory must be specified using -srcdir: " + baseSrcDir); + return; + } + if (baseSrcDir.isDirectory() == false) { + System.out.println("Source does not exist or is not a directory: " + baseSrcDir); + return; + } + dstDir = (dstDir != null ? dstDir : baseSrcDir); + + // parse source file names + List srcFileNames = Arrays.asList(Arrays.copyOfRange(args, i, args.length)); + if (srcFileNames.isEmpty()) { + System.out.println("Source filenames not specified, using default set"); + System.out.println("(africa antarctica asia australasia backward etcetera europe northamerica southamerica)"); + srcFileNames = Arrays.asList("africa", "antarctica", "asia", "australasia", "backward", + "etcetera", "europe", "northamerica", "southamerica"); + } + + // find source directories to process + List srcDirs = new ArrayList<>(); + if (version != null) { + // if the "version" specified, as in jdk repo, the "baseSrcDir" is + // the "srcDir" that contains the tzdb data. + srcDirs.add(baseSrcDir); + } else { + File[] dirs = baseSrcDir.listFiles(); + for (File dir : dirs) { + if (dir.isDirectory() && dir.getName().matches("[12][0-9]{3}[A-Za-z0-9._-]+")) { + srcDirs.add(dir); + } + } + } + if (srcDirs.isEmpty()) { + System.out.println("Source directory contains no valid source folders: " + baseSrcDir); + return; + } + // check destination directory + if (dstDir.exists() == false && dstDir.mkdirs() == false) { + System.out.println("Destination directory could not be created: " + dstDir); + return; + } + if (dstDir.isDirectory() == false) { + System.out.println("Destination is not a directory: " + dstDir); + return; + } + process(srcDirs, srcFileNames, dstDir, version, verbose); + System.exit(0); + } + + /** + * Output usage text for the command line. + */ + private static void outputHelp() { + System.out.println("Usage: TzdbZoneRulesCompiler "); + System.out.println("where options include:"); + System.out.println(" -srcdir Where to find source directories (required)"); + System.out.println(" -dstdir Where to output generated files (default srcdir)"); + System.out.println(" -version Specify the version, such as 2009a (optional)"); + System.out.println(" -help Print this usage message"); + System.out.println(" -verbose Output verbose information during compilation"); + System.out.println(" There must be one directory for each version in srcdir"); + System.out.println(" Each directory must have the name of the version, such as 2009a"); + System.out.println(" Each directory must contain the unpacked tzdb files, such as asia or europe"); + System.out.println(" Directories must match the regex [12][0-9][0-9][0-9][A-Za-z0-9._-]+"); + System.out.println(" There will be one jar file for each version and one combined jar in dstdir"); + System.out.println(" If the version is specified, only that version is processed"); + } + + /** + * Process to create the jar files. + */ + private static void process(List srcDirs, List srcFileNames, File dstDir, String version, boolean verbose) { + // build actual jar files + Map> allBuiltZones = new TreeMap<>(); + Set allRegionIds = new TreeSet(); + Set allRules = new HashSet(); + + for (File srcDir : srcDirs) { + // source files in this directory + List srcFiles = new ArrayList<>(); + for (String srcFileName : srcFileNames) { + File file = new File(srcDir, srcFileName); + if (file.exists()) { + srcFiles.add(file); + } + } + if (srcFiles.isEmpty()) { + continue; // nothing to process + } + + // compile + String loopVersion = srcDir.getName(); + TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose); + try { + // compile + compiler.compile(); + SortedMap builtZones = compiler.getZones(); + + // output version-specific file + File dstFile = version == null ? new File(dstDir, "tzdb" + loopVersion + ".jar") + : new File(dstDir, "tzdb.jar"); + if (verbose) { + System.out.println("Outputting file: " + dstFile); + } + outputFile(dstFile, loopVersion, builtZones); + + // create totals + allBuiltZones.put(loopVersion, builtZones); + allRegionIds.addAll(builtZones.keySet()); + allRules.addAll(builtZones.values()); + } catch (Exception ex) { + System.out.println("Failed: " + ex.toString()); + ex.printStackTrace(); + System.exit(1); + } + } + + // output merged file + if (version == null) { + File dstFile = new File(dstDir, "tzdb-all.jar"); + if (verbose) { + System.out.println("Outputting combined file: " + dstFile); + } + outputFile(dstFile, allBuiltZones, allRegionIds, allRules); + } + } + + /** + * Outputs the file. + */ + private static void outputFile(File dstFile, + String version, + SortedMap builtZones) { + Map> loopAllBuiltZones = new TreeMap<>(); + loopAllBuiltZones.put(version, builtZones); + Set loopAllRegionIds = new TreeSet(builtZones.keySet()); + Set loopAllRules = new HashSet(builtZones.values()); + outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules); + } + + /** + * Outputs the file. + */ + private static void outputFile(File dstFile, + Map> allBuiltZones, + Set allRegionIds, + Set allRules) + { + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) { + outputTZEntry(jos, allBuiltZones, allRegionIds, allRules); + } catch (Exception ex) { + System.out.println("Failed: " + ex.toString()); + ex.printStackTrace(); + System.exit(1); + } + } + + /** + * Outputs the timezone entry in the JAR file. + */ + private static void outputTZEntry(JarOutputStream jos, + Map> allBuiltZones, + Set allRegionIds, + Set allRules) { + // this format is not publicly specified + try { + jos.putNextEntry(new ZipEntry("TZDB.dat")); + DataOutputStream out = new DataOutputStream(jos); + + // file version + out.writeByte(1); + // group + out.writeUTF("TZDB"); + // versions + String[] versionArray = allBuiltZones.keySet().toArray(new String[allBuiltZones.size()]); + out.writeShort(versionArray.length); + for (String version : versionArray) { + out.writeUTF(version); + } + // regions + String[] regionArray = allRegionIds.toArray(new String[allRegionIds.size()]); + out.writeShort(regionArray.length); + for (String regionId : regionArray) { + out.writeUTF(regionId); + } + // rules + List rulesList = new ArrayList<>(allRules); + out.writeShort(rulesList.size()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + for (ZoneRules rules : rulesList) { + baos.reset(); + DataOutputStream dataos = new DataOutputStream(baos); + rules.writeExternal(dataos); + dataos.close(); + byte[] bytes = baos.toByteArray(); + out.writeShort(bytes.length); + out.write(bytes); + } + // link version-region-rules + for (String version : allBuiltZones.keySet()) { + out.writeShort(allBuiltZones.get(version).size()); + for (Map.Entry entry : allBuiltZones.get(version).entrySet()) { + int regionIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int rulesIndex = rulesList.indexOf(entry.getValue()); + out.writeShort(regionIndex); + out.writeShort(rulesIndex); + } + } + out.flush(); + jos.closeEntry(); + } catch (Exception ex) { + System.out.println("Failed: " + ex.toString()); + ex.printStackTrace(); + System.exit(1); + } + } + + //----------------------------------------------------------------------- + /** The TZDB rules. */ + private final Map> rules = new HashMap<>(); + + /** The TZDB zones. */ + private final Map> zones = new HashMap<>(); + /** The TZDB links. */ + + private final Map links = new HashMap<>(); + + /** The built zones. */ + private final SortedMap builtZones = new TreeMap<>(); + + + /** The version to produce. */ + private final String version; + + /** The source files. */ + + private final List sourceFiles; + + /** The version to produce. */ + private final boolean verbose; + + /** + * Creates an instance if you want to invoke the compiler manually. + * + * @param version the version, such as 2009a, not null + * @param sourceFiles the list of source files, not empty, not null + * @param verbose whether to output verbose messages + */ + public TzdbZoneRulesCompiler(String version, List sourceFiles, boolean verbose) { + this.version = version; + this.sourceFiles = sourceFiles; + this.verbose = verbose; + } + + /** + * Compile the rules file. + *

+ * Use {@link #getZones()} to retrieve the parsed data. + * + * @throws Exception if an error occurs + */ + public void compile() throws Exception { + printVerbose("Compiling TZDB version " + version); + parseFiles(); + buildZoneRules(); + printVerbose("Compiled TZDB version " + version); + } + + /** + * Gets the parsed zone rules. + * + * @return the parsed zone rules, not null + */ + public SortedMap getZones() { + return builtZones; + } + + /** + * Parses the source files. + * + * @throws Exception if an error occurs + */ + private void parseFiles() throws Exception { + for (File file : sourceFiles) { + printVerbose("Parsing file: " + file); + parseFile(file); + } + } + + /** + * Parses a source file. + * + * @param file the file being read, not null + * @throws Exception if an error occurs + */ + private void parseFile(File file) throws Exception { + int lineNumber = 1; + String line = null; + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(file)); + List openZone = null; + for ( ; (line = in.readLine()) != null; lineNumber++) { + int index = line.indexOf('#'); // remove comments (doesn't handle # in quotes) + if (index >= 0) { + line = line.substring(0, index); + } + if (line.trim().length() == 0) { // ignore blank lines + continue; + } + StringTokenizer st = new StringTokenizer(line, " \t"); + if (openZone != null && Character.isWhitespace(line.charAt(0)) && st.hasMoreTokens()) { + if (parseZoneLine(st, openZone)) { + openZone = null; + } + } else { + if (st.hasMoreTokens()) { + String first = st.nextToken(); + if (first.equals("Zone")) { + if (st.countTokens() < 3) { + printVerbose("Invalid Zone line in file: " + file + ", line: " + line); + throw new IllegalArgumentException("Invalid Zone line"); + } + openZone = new ArrayList<>(); + zones.put(st.nextToken(), openZone); + if (parseZoneLine(st, openZone)) { + openZone = null; + } + } else { + openZone = null; + if (first.equals("Rule")) { + if (st.countTokens() < 9) { + printVerbose("Invalid Rule line in file: " + file + ", line: " + line); + throw new IllegalArgumentException("Invalid Rule line"); + } + parseRuleLine(st); + + } else if (first.equals("Link")) { + if (st.countTokens() < 2) { + printVerbose("Invalid Link line in file: " + file + ", line: " + line); + throw new IllegalArgumentException("Invalid Link line"); + } + String realId = st.nextToken(); + String aliasId = st.nextToken(); + links.put(aliasId, realId); + + } else { + throw new IllegalArgumentException("Unknown line"); + } + } + } + } + } + } catch (Exception ex) { + throw new Exception("Failed while processing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (Exception ex) { + // ignore NPE and IOE + } + } + } + + /** + * Parses a Rule line. + * + * @param st the tokenizer, not null + */ + private void parseRuleLine(StringTokenizer st) { + TZDBRule rule = new TZDBRule(); + String name = st.nextToken(); + if (rules.containsKey(name) == false) { + rules.put(name, new ArrayList()); + } + rules.get(name).add(rule); + rule.startYear = parseYear(st.nextToken(), 0); + rule.endYear = parseYear(st.nextToken(), rule.startYear); + if (rule.startYear > rule.endYear) { + throw new IllegalArgumentException("Year order invalid: " + rule.startYear + " > " + rule.endYear); + } + parseOptional(st.nextToken()); // type is unused + parseMonthDayTime(st, rule); + rule.savingsAmount = parsePeriod(st.nextToken()); + rule.text = parseOptional(st.nextToken()); + } + + /** + * Parses a Zone line. + * + * @param st the tokenizer, not null + * @return true if the zone is complete + */ + private boolean parseZoneLine(StringTokenizer st, List zoneList) { + TZDBZone zone = new TZDBZone(); + zoneList.add(zone); + zone.standardOffset = parseOffset(st.nextToken()); + String savingsRule = parseOptional(st.nextToken()); + if (savingsRule == null) { + zone.fixedSavingsSecs = 0; + zone.savingsRule = null; + } else { + try { + zone.fixedSavingsSecs = parsePeriod(savingsRule); + zone.savingsRule = null; + } catch (Exception ex) { + zone.fixedSavingsSecs = null; + zone.savingsRule = savingsRule; + } + } + zone.text = st.nextToken(); + if (st.hasMoreTokens()) { + zone.year = Integer.parseInt(st.nextToken()); + if (st.hasMoreTokens()) { + parseMonthDayTime(st, zone); + } + return false; + } else { + return true; + } + } + + /** + * Parses a Rule line. + * + * @param st the tokenizer, not null + * @param mdt the object to parse into, not null + */ + private void parseMonthDayTime(StringTokenizer st, TZDBMonthDayTime mdt) { + mdt.month = parseMonth(st.nextToken()); + if (st.hasMoreTokens()) { + String dayRule = st.nextToken(); + if (dayRule.startsWith("last")) { + mdt.dayOfMonth = -1; + mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(4)); + mdt.adjustForwards = false; + } else { + int index = dayRule.indexOf(">="); + if (index > 0) { + mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index)); + dayRule = dayRule.substring(index + 2); + } else { + index = dayRule.indexOf("<="); + if (index > 0) { + mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index)); + mdt.adjustForwards = false; + dayRule = dayRule.substring(index + 2); + } + } + mdt.dayOfMonth = Integer.parseInt(dayRule); + } + if (st.hasMoreTokens()) { + String timeStr = st.nextToken(); + int secsOfDay = parseSecs(timeStr); + if (secsOfDay == 86400) { + mdt.endOfDay = true; + secsOfDay = 0; + } + LocalTime time = LocalTime.ofSecondOfDay(secsOfDay); + mdt.time = time; + mdt.timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1)); + } + } + } + + private int parseYear(String str, int defaultYear) { + if (YEAR.reset(str).matches()) { + if (YEAR.group("min") != null) { + return YEAR_MIN_VALUE; + } else if (YEAR.group("max") != null) { + return YEAR_MAX_VALUE; + } else if (YEAR.group("only") != null) { + return defaultYear; + } + return Integer.parseInt(YEAR.group("year")); + } + throw new IllegalArgumentException("Unknown year: " + str); + } + + private int parseMonth(String str) { + if (MONTH.reset(str).matches()) { + for (int moy = 1; moy < 13; moy++) { + if (MONTH.group(moy) != null) { + return moy; + } + } + } + throw new IllegalArgumentException("Unknown month: " + str); + } + + private int parseDayOfWeek(String str) { + if (DOW.reset(str).matches()) { + for (int dow = 1; dow < 8; dow++) { + if (DOW.group(dow) != null) { + return dow; + } + } + } + throw new IllegalArgumentException("Unknown day-of-week: " + str); + } + + private String parseOptional(String str) { + return str.equals("-") ? null : str; + } + + private int parseSecs(String str) { + if (str.equals("-")) { + return 0; + } + try { + if (TIME.reset(str).find()) { + int secs = Integer.parseInt(TIME.group("hour")) * 60 * 60; + if (TIME.group("minute") != null) { + secs += Integer.parseInt(TIME.group("minute")) * 60; + } + if (TIME.group("second") != null) { + secs += Integer.parseInt(TIME.group("second")); + } + if (TIME.group("neg") != null) { + secs = -secs; + } + return secs; + } + } catch (NumberFormatException x) {} + throw new IllegalArgumentException(str); + } + + private ZoneOffset parseOffset(String str) { + int secs = parseSecs(str); + return ZoneOffset.ofTotalSeconds(secs); + } + + private int parsePeriod(String str) { + return parseSecs(str); + } + + private TimeDefinition parseTimeDefinition(char c) { + switch (c) { + case 's': + case 'S': + // standard time + return TimeDefinition.STANDARD; + case 'u': + case 'U': + case 'g': + case 'G': + case 'z': + case 'Z': + // UTC + return TimeDefinition.UTC; + case 'w': + case 'W': + default: + // wall time + return TimeDefinition.WALL; + } + } + + //----------------------------------------------------------------------- + /** + * Build the rules, zones and links into real zones. + * + * @throws Exception if an error occurs + */ + private void buildZoneRules() throws Exception { + // build zones + for (String zoneId : zones.keySet()) { + printVerbose("Building zone " + zoneId); + List tzdbZones = zones.get(zoneId); + ZoneRulesBuilder bld = new ZoneRulesBuilder(); + for (TZDBZone tzdbZone : tzdbZones) { + bld = tzdbZone.addToBuilder(bld, rules); + } + ZoneRules buildRules = bld.toRules(zoneId); + builtZones.put(zoneId, buildRules); + } + + // build aliases + for (String aliasId : links.keySet()) { + String realId = links.get(aliasId); + printVerbose("Linking alias " + aliasId + " to " + realId); + ZoneRules realRules = builtZones.get(realId); + if (realRules == null) { + realId = links.get(realId); // try again (handle alias liked to alias) + printVerbose("Relinking alias " + aliasId + " to " + realId); + realRules = builtZones.get(realId); + if (realRules == null) { + throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'"); + } + } + builtZones.put(aliasId, realRules); + } + + // remove UTC and GMT + builtZones.remove("UTC"); + builtZones.remove("GMT"); + builtZones.remove("GMT0"); + builtZones.remove("GMT+0"); + builtZones.remove("GMT-0"); + } + + //----------------------------------------------------------------------- + /** + * Prints a verbose message. + * + * @param message the message, not null + */ + private void printVerbose(String message) { + if (verbose) { + System.out.println(message); + } + } + + //----------------------------------------------------------------------- + /** + * Class representing a month-day-time in the TZDB file. + */ + abstract class TZDBMonthDayTime { + /** The month of the cutover. */ + int month = 1; + /** The day-of-month of the cutover. */ + int dayOfMonth = 1; + /** Whether to adjust forwards. */ + boolean adjustForwards = true; + /** The day-of-week of the cutover. */ + int dayOfWeek = -1; + /** The time of the cutover. */ + LocalTime time = LocalTime.MIDNIGHT; + /** Whether this is midnight end of day. */ + boolean endOfDay; + /** The time of the cutover. */ + TimeDefinition timeDefinition = TimeDefinition.WALL; + + void adjustToFowards(int year) { + if (adjustForwards == false && dayOfMonth > 0) { + LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6); + dayOfMonth = adjustedDate.getDayOfMonth(); + month = adjustedDate.getMonth(); + adjustForwards = true; + } + } + } + + /** + * Class representing a rule line in the TZDB file. + */ + final class TZDBRule extends TZDBMonthDayTime { + /** The start year. */ + int startYear; + /** The end year. */ + int endYear; + /** The amount of savings. */ + int savingsAmount; + /** The text name of the zone. */ + String text; + + void addToBuilder(ZoneRulesBuilder bld) { + adjustToFowards(2004); // irrelevant, treat as leap year + bld.addRuleToWindow(startYear, endYear, month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, savingsAmount); + } + } + + /** + * Class representing a linked set of zone lines in the TZDB file. + */ + final class TZDBZone extends TZDBMonthDayTime { + /** The standard offset. */ + ZoneOffset standardOffset; + /** The fixed savings amount. */ + Integer fixedSavingsSecs; + /** The savings rule. */ + String savingsRule; + /** The text name of the zone. */ + String text; + /** The year of the cutover. */ + int year = YEAR_MAX_VALUE; + + ZoneRulesBuilder addToBuilder(ZoneRulesBuilder bld, Map> rules) { + if (year != YEAR_MAX_VALUE) { + bld.addWindow(standardOffset, toDateTime(year), timeDefinition); + } else { + bld.addWindowForever(standardOffset); + } + if (fixedSavingsSecs != null) { + bld.setFixedSavingsToWindow(fixedSavingsSecs); + } else { + List tzdbRules = rules.get(savingsRule); + if (tzdbRules == null) { + throw new IllegalArgumentException("Rule not found: " + savingsRule); + } + for (TZDBRule tzdbRule : tzdbRules) { + tzdbRule.addToBuilder(bld); + } + } + return bld; + } + + private LocalDateTime toDateTime(int year) { + adjustToFowards(year); + LocalDate date; + if (dayOfMonth == -1) { + dayOfMonth = lengthOfMonth(month, isLeapYear(year)); + date = LocalDate.of(year, month, dayOfMonth); + if (dayOfWeek != -1) { + date = previousOrSame(date, dayOfWeek); + } + } else { + date = LocalDate.of(year, month, dayOfMonth); + if (dayOfWeek != -1) { + date = nextOrSame(date, dayOfWeek); + } + } + LocalDateTime ldt = LocalDateTime.of(date, time); + if (endOfDay) { + ldt = ldt.plusDays(1); + } + return ldt; + } + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/Utils.java b/jdk/make/tools/src/build/tools/tzdb/Utils.java new file mode 100644 index 00000000000..d129dd3bc7f --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/Utils.java @@ -0,0 +1,176 @@ +/* + * 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) 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 build.tools.tzdb; + +import java.util.Objects; + +class Utils { + + // Returns the largest (closest to positive infinity) + public static long floorDiv(long x, long y) { + long r = x / y; + // if the signs are different and modulo not zero, round down + if ((x ^ y) < 0 && (r * y != x)) { + r--; + } + return r; + } + + // Returns the floor modulus of the {@code long} arguments. + public static long floorMod(long x, long y) { + return x - floorDiv(x, y) * y; + } + + // Returns the sum of its arguments, + public static long addExact(long x, long y) { + long r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("long overflow"); + } + return r; + } + + // Year + + // Returns true if the specified year is a leap year. + public static boolean isLeapYear(int year) { + return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); + } + + // The minimum supported year, '-999,999,999'. + public static final int YEAR_MIN_VALUE = -999_999_999; + + // The maximum supported year, '+999,999,999'. + public static final int YEAR_MAX_VALUE = 999_999_999; + + + // Gets the length of the specified month in days. + public static int lengthOfMonth(int month, boolean leapYear) { + switch (month) { + case 2: //FEBRUARY: + return (leapYear ? 29 : 28); + case 4: //APRIL: + case 6: //JUNE: + case 9: //SEPTEMBER: + case 11: //NOVEMBER: + return 30; + default: + return 31; + } + } + + // Gets the maximum length of the specified month in days. + public static int maxLengthOfMonth(int month) { + switch (month) { + case 2: //FEBRUARY: + return 29; + case 4: //APRIL: + case 6: //JUNE: + case 9: //SEPTEMBER: + case 11: //NOVEMBER: + return 30; + default: + return 31; + } + } + + // DayOfWeek + + // Returns the day-of-week that is the specified number of days after + // this one, from 1 to 7 for Monday to Sunday. + public static int plusDayOfWeek(int dow, long days) { + int amount = (int) (days % 7); + return (dow - 1 + (amount + 7)) % 7 + 1; + } + + // Returns the day-of-week that is the specified number of days before + // this one, from 1 to 7 for Monday to Sunday. + public static int minusDayOfWeek(int dow, long days) { + return plusDayOfWeek(dow, -(days % 7)); + } + + // Adjusts the date to the first occurrence of the specified day-of-week + // before the date being adjusted unless it is already on that day in + // which case the same object is returned. + public static LocalDate previousOrSame(LocalDate date, int dayOfWeek) { + return adjust(date, dayOfWeek, 1); + } + + // Adjusts the date to the first occurrence of the specified day-of-week + // after the date being adjusted unless it is already on that day in + // which case the same object is returned. + public static LocalDate nextOrSame(LocalDate date, int dayOfWeek) { + return adjust(date, dayOfWeek, 0); + } + + // Implementation of next, previous or current day-of-week. + // @param relative whether the current date is a valid answer + private static final LocalDate adjust(LocalDate date, int dow, int relative) { + int calDow = date.getDayOfWeek(); + if (relative < 2 && calDow == dow) { + return date; + } + if ((relative & 1) == 0) { + int daysDiff = calDow - dow; + return date.plusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff); + } else { + int daysDiff = dow - calDow; + return date.minusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff); + } + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/ZoneOffset.java b/jdk/make/tools/src/build/tools/tzdb/ZoneOffset.java new file mode 100644 index 00000000000..4f95fb3dd59 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffset.java @@ -0,0 +1,474 @@ +/* + * 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. + */ + +/* + * 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) 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 build.tools.tzdb; + +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A time-zone offset from Greenwich/UTC, such as {@code +02:00}. + *

+ * A time-zone offset is the period of time that a time-zone differs from Greenwich/UTC. + * This is usually a fixed number of hours and minutes. + * + * @since 1.8 + */ +final class ZoneOffset implements Comparable { + + /** Cache of time-zone offset by offset in seconds. */ + private static final ConcurrentMap SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4); + /** Cache of time-zone offset by ID. */ + private static final ConcurrentMap ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4); + + /** + * The number of seconds per hour. + */ + private static final int SECONDS_PER_HOUR = 60 * 60; + /** + * The number of seconds per minute. + */ + private static final int SECONDS_PER_MINUTE = 60; + /** + * The number of minutes per hour. + */ + private static final int MINUTES_PER_HOUR = 60; + /** + * The abs maximum seconds. + */ + private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR; + /** + * Serialization version. + */ + private static final long serialVersionUID = 2357656521762053153L; + + /** + * The time-zone offset for UTC, with an ID of 'Z'. + */ + public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0); + /** + * Constant for the maximum supported offset. + */ + public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS); + /** + * Constant for the maximum supported offset. + */ + public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS); + + /** + * The total offset in seconds. + */ + private final int totalSeconds; + /** + * The string form of the time-zone offset. + */ + private final transient String id; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code ZoneOffset} using the ID. + *

+ * This method parses the string ID of a {@code ZoneOffset} to + * return an instance. The parsing accepts all the formats generated by + * {@link #getId()}, plus some additional formats: + *

    + *
  • {@code Z} - for UTC + *
  • {@code +h} + *
  • {@code +hh} + *
  • {@code +hh:mm} + *
  • {@code -hh:mm} + *
  • {@code +hhmm} + *
  • {@code -hhmm} + *
  • {@code +hh:mm:ss} + *
  • {@code -hh:mm:ss} + *
  • {@code +hhmmss} + *
  • {@code -hhmmss} + *

+ * Note that ± means either the plus or minus symbol. + *

+ * The ID of the returned offset will be normalized to one of the formats + * described by {@link #getId()}. + *

+ * The maximum supported range is from +18:00 to -18:00 inclusive. + * + * @param offsetId the offset ID, not null + * @return the zone-offset, not null + * @throws DateTimeException if the offset ID is invalid + */ + @SuppressWarnings("fallthrough") + public static ZoneOffset of(String offsetId) { + Objects.requireNonNull(offsetId, "offsetId"); + // "Z" is always in the cache + ZoneOffset offset = ID_CACHE.get(offsetId); + if (offset != null) { + return offset; + } + + // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss + final int hours, minutes, seconds; + switch (offsetId.length()) { + case 2: + offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru + case 3: + hours = parseNumber(offsetId, 1, false); + minutes = 0; + seconds = 0; + break; + case 5: + hours = parseNumber(offsetId, 1, false); + minutes = parseNumber(offsetId, 3, false); + seconds = 0; + break; + case 6: + hours = parseNumber(offsetId, 1, false); + minutes = parseNumber(offsetId, 4, true); + seconds = 0; + break; + case 7: + hours = parseNumber(offsetId, 1, false); + minutes = parseNumber(offsetId, 3, false); + seconds = parseNumber(offsetId, 5, false); + break; + case 9: + hours = parseNumber(offsetId, 1, false); + minutes = parseNumber(offsetId, 4, true); + seconds = parseNumber(offsetId, 7, true); + break; + default: + throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid"); + } + char first = offsetId.charAt(0); + if (first != '+' && first != '-') { + throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected"); + } + if (first == '-') { + return ofHoursMinutesSeconds(-hours, -minutes, -seconds); + } else { + return ofHoursMinutesSeconds(hours, minutes, seconds); + } + } + + /** + * Parse a two digit zero-prefixed number. + * + * @param offsetId the offset ID, not null + * @param pos the position to parse, valid + * @param precededByColon should this number be prefixed by a precededByColon + * @return the parsed number, from 0 to 99 + */ + private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) { + if (precededByColon && offsetId.charAt(pos - 1) != ':') { + throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected"); + } + char ch1 = offsetId.charAt(pos); + char ch2 = offsetId.charAt(pos + 1); + if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') { + throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found"); + } + return (ch1 - 48) * 10 + (ch2 - 48); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code ZoneOffset} using an offset in hours. + * + * @param hours the time-zone offset in hours, from -18 to +18 + * @return the zone-offset, not null + * @throws DateTimeException if the offset is not in the required range + */ + public static ZoneOffset ofHours(int hours) { + return ofHoursMinutesSeconds(hours, 0, 0); + } + + /** + * Obtains an instance of {@code ZoneOffset} using an offset in + * hours and minutes. + *

+ * The sign of the hours and minutes components must match. + * Thus, if the hours is negative, the minutes must be negative or zero. + * If the hours is zero, the minutes may be positive, negative or zero. + * + * @param hours the time-zone offset in hours, from -18 to +18 + * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours + * @return the zone-offset, not null + * @throws DateTimeException if the offset is not in the required range + */ + public static ZoneOffset ofHoursMinutes(int hours, int minutes) { + return ofHoursMinutesSeconds(hours, minutes, 0); + } + + /** + * Obtains an instance of {@code ZoneOffset} using an offset in + * hours, minutes and seconds. + *

+ * The sign of the hours, minutes and seconds components must match. + * Thus, if the hours is negative, the minutes and seconds must be negative or zero. + * + * @param hours the time-zone offset in hours, from -18 to +18 + * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds + * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes + * @return the zone-offset, not null + * @throws DateTimeException if the offset is not in the required range + */ + public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) { + validate(hours, minutes, seconds); + int totalSeconds = totalSeconds(hours, minutes, seconds); + return ofTotalSeconds(totalSeconds); + } + + /** + * Validates the offset fields. + * + * @param hours the time-zone offset in hours, from -18 to +18 + * @param minutes the time-zone offset in minutes, from 0 to ±59 + * @param seconds the time-zone offset in seconds, from 0 to ±59 + * @throws DateTimeException if the offset is not in the required range + */ + private static void validate(int hours, int minutes, int seconds) { + if (hours < -18 || hours > 18) { + throw new DateTimeException("Zone offset hours not in valid range: value " + hours + + " is not in the range -18 to 18"); + } + if (hours > 0) { + if (minutes < 0 || seconds < 0) { + throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive"); + } + } else if (hours < 0) { + if (minutes > 0 || seconds > 0) { + throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative"); + } + } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) { + throw new DateTimeException("Zone offset minutes and seconds must have the same sign"); + } + if (Math.abs(minutes) > 59) { + throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " + + Math.abs(minutes) + " is not in the range 0 to 59"); + } + if (Math.abs(seconds) > 59) { + throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " + + Math.abs(seconds) + " is not in the range 0 to 59"); + } + if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) { + throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00"); + } + } + + /** + * Calculates the total offset in seconds. + * + * @param hours the time-zone offset in hours, from -18 to +18 + * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds + * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes + * @return the total in seconds + */ + private static int totalSeconds(int hours, int minutes, int seconds) { + return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds; + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds + *

+ * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800. + * + * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + * @return the ZoneOffset, not null + * @throws DateTimeException if the offset is not in the required range + */ + public static ZoneOffset ofTotalSeconds(int totalSeconds) { + if (Math.abs(totalSeconds) > MAX_SECONDS) { + throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00"); + } + if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) { + Integer totalSecs = totalSeconds; + ZoneOffset result = SECONDS_CACHE.get(totalSecs); + if (result == null) { + result = new ZoneOffset(totalSeconds); + SECONDS_CACHE.putIfAbsent(totalSecs, result); + result = SECONDS_CACHE.get(totalSecs); + ID_CACHE.putIfAbsent(result.getId(), result); + } + return result; + } else { + return new ZoneOffset(totalSeconds); + } + } + + /** + * Constructor. + * + * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + */ + private ZoneOffset(int totalSeconds) { + super(); + this.totalSeconds = totalSeconds; + id = buildId(totalSeconds); + } + + private static String buildId(int totalSeconds) { + if (totalSeconds == 0) { + return "Z"; + } else { + int absTotalSeconds = Math.abs(totalSeconds); + StringBuilder buf = new StringBuilder(); + int absHours = absTotalSeconds / SECONDS_PER_HOUR; + int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; + buf.append(totalSeconds < 0 ? "-" : "+") + .append(absHours < 10 ? "0" : "").append(absHours) + .append(absMinutes < 10 ? ":0" : ":").append(absMinutes); + int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE; + if (absSeconds != 0) { + buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds); + } + return buf.toString(); + } + } + + /** + * Gets the total zone offset in seconds. + *

+ * This is the primary way to access the offset amount. + * It returns the total of the hours, minutes and seconds fields as a + * single offset that can be added to a time. + * + * @return the total zone offset amount in seconds + */ + public int getTotalSeconds() { + return totalSeconds; + } + + /** + * Gets the normalized zone offset ID. + *

+ * The ID is minor variation to the standard ISO-8601 formatted string + * for the offset. There are three formats: + *

    + *
  • {@code Z} - for UTC (ISO-8601) + *
  • {@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601) + *
  • {@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601) + *

+ * + * @return the zone offset ID, not null + */ + public String getId() { + return id; + } + + /** + * Compares this offset to another offset in descending order. + *

+ * The offsets are compared in the order that they occur for the same time + * of day around the world. Thus, an offset of {@code +10:00} comes before an + * offset of {@code +09:00} and so on down to {@code -18:00}. + *

+ * The comparison is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, postive if greater + * @throws NullPointerException if {@code other} is null + */ + @Override + public int compareTo(ZoneOffset other) { + return other.totalSeconds - totalSeconds; + } + + /** + * Checks if this offset is equal to another offset. + *

+ * The comparison is based on the amount of the offset in seconds. + * This is equivalent to a comparison by ID. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other offset + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ZoneOffset) { + return totalSeconds == ((ZoneOffset) obj).totalSeconds; + } + return false; + } + + /** + * A hash code for this offset. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return totalSeconds; + } + + /** + * Outputs this offset as a {@code String}, using the normalized ID. + * + * @return a string representation of this offset, not null + */ + @Override + public String toString() { + return id; + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java new file mode 100644 index 00000000000..167b5f112de --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java @@ -0,0 +1,290 @@ +/* + * 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. + */ + +/* + * 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 build.tools.tzdb; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A transition between two offsets caused by a discontinuity in the local time-line. + * + * @since 1.8 + */ +final class ZoneOffsetTransition implements Comparable { + + /** + * The local transition date-time at the transition. + */ + private final LocalDateTime transition; + /** + * The offset before transition. + */ + private final ZoneOffset offsetBefore; + /** + * The offset after transition. + */ + private final ZoneOffset offsetAfter; + + /** + * Creates an instance defining a transition between two offsets. + * + * @param transition the transition date-time with the offset before the transition, not null + * @param offsetBefore the offset before the transition, not null + * @param offsetAfter the offset at and after the transition, not null + */ + ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) { + Objects.requireNonNull(transition, "transition"); + Objects.requireNonNull(offsetBefore, "offsetBefore"); + Objects.requireNonNull(offsetAfter, "offsetAfter"); + if (offsetBefore.equals(offsetAfter)) { + throw new IllegalArgumentException("Offsets must not be equal"); + } + this.transition = transition; + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + /** + * Creates an instance from epoch-second and offsets. + * + * @param epochSecond the transition epoch-second + * @param offsetBefore the offset before the transition, not null + * @param offsetAfter the offset at and after the transition, not null + */ + ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) { + this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore); + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + /** + * Gets the transition instant as an epoch second. + * + * @return the transition epoch second + */ + public long toEpochSecond() { + return transition.toEpochSecond(offsetBefore); + } + + /** + * Gets the local transition date-time, as would be expressed with the 'before' offset. + *

+ * This is the date-time where the discontinuity begins expressed with the 'before' offset. + * At this instant, the 'after' offset is actually used, therefore the combination of this + * date-time and the 'before' offset will never occur. + *

+ * The combination of the 'before' date-time and offset represents the same instant + * as the 'after' date-time and offset. + * + * @return the transition date-time expressed with the before offset, not null + */ + public LocalDateTime getDateTimeBefore() { + return transition; + } + + /** + * Gets the local transition date-time, as would be expressed with the 'after' offset. + *

+ * This is the first date-time after the discontinuity, when the new offset applies. + *

+ * The combination of the 'before' date-time and offset represents the same instant + * as the 'after' date-time and offset. + * + * @return the transition date-time expressed with the after offset, not null + */ + public LocalDateTime getDateTimeAfter() { + return transition.plusSeconds(getDurationSeconds()); + } + + /** + * Gets the offset before the transition. + *

+ * This is the offset in use before the instant of the transition. + * + * @return the offset before the transition, not null + */ + public ZoneOffset getOffsetBefore() { + return offsetBefore; + } + + /** + * Gets the offset after the transition. + *

+ * This is the offset in use on and after the instant of the transition. + * + * @return the offset after the transition, not null + */ + public ZoneOffset getOffsetAfter() { + return offsetAfter; + } + + /** + * Gets the duration of the transition in seconds. + * + * @return the duration in seconds + */ + private int getDurationSeconds() { + return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds(); + } + + /** + * Does this transition represent a gap in the local time-line. + *

+ * Gaps occur where there are local date-times that simply do not not exist. + * An example would be when the offset changes from {@code +01:00} to {@code +02:00}. + * This might be described as 'the clocks will move forward one hour tonight at 1am'. + * + * @return true if this transition is a gap, false if it is an overlap + */ + public boolean isGap() { + return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds(); + } + + /** + * Does this transition represent a gap in the local time-line. + *

+ * Overlaps occur where there are local date-times that exist twice. + * An example would be when the offset changes from {@code +02:00} to {@code +01:00}. + * This might be described as 'the clocks will move back one hour tonight at 2am'. + * + * @return true if this transition is an overlap, false if it is a gap + */ + public boolean isOverlap() { + return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds(); + } + + /** + * Checks if the specified offset is valid during this transition. + *

+ * This checks to see if the given offset will be valid at some point in the transition. + * A gap will always return false. + * An overlap will return true if the offset is either the before or after offset. + * + * @param offset the offset to check, null returns false + * @return true if the offset is valid during the transition + */ + public boolean isValidOffset(ZoneOffset offset) { + return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset)); + } + + /** + * Gets the valid offsets during this transition. + *

+ * A gap will return an empty list, while an overlap will return both offsets. + * + * @return the list of valid offsets + */ + List getValidOffsets() { + if (isGap()) { + return Collections.emptyList(); + } + return Arrays.asList(getOffsetBefore(), getOffsetAfter()); + } + + /** + * Compares this transition to another based on the transition instant. + *

+ * This compares the instants of each transition. + * The offsets are ignored, making this order inconsistent with equals. + * + * @param transition the transition to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(ZoneOffsetTransition transition) { + return Long.compare(this.toEpochSecond(), transition.toEpochSecond()); + } + + /** + * Checks if this object equals another. + *

+ * The entire state of the object is compared. + * + * @param other the other object to compare to, null returns false + * @return true if equal + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other instanceof ZoneOffsetTransition) { + ZoneOffsetTransition d = (ZoneOffsetTransition) other; + return transition.equals(d.transition) && + offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter); + } + return false; + } + + /** + * Returns a suitable hash code. + * + * @return the hash code + */ + @Override + public int hashCode() { + return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java new file mode 100644 index 00000000000..783499c2163 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.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. 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: + * + * 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 build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; +import java.util.Objects; + +/** + * A rule expressing how to create a transition. + *

+ * This class allows rules for identifying future transitions to be expressed. + * A rule might be written in many forms: + *

    + *
  • the 16th March + *
  • the Sunday on or after the 16th March + *
  • the Sunday on or before the 16th March + *
  • the last Sunday in February + *

+ * These different rule types can be expressed and queried. + * + *

Specification for implementors

+ * This class is immutable and thread-safe. + * + * @since 1.8 + */ +final class ZoneOffsetTransitionRule { + + /** + * The month of the month-day of the first day of the cutover week. + * The actual date will be adjusted by the dowChange field. + */ + final int month; + /** + * The day-of-month of the month-day of the cutover week. + * If positive, it is the start of the week where the cutover can occur. + * If negative, it represents the end of the week where cutover can occur. + * The value is the number of days from the end of the month, such that + * {@code -1} is the last day of the month, {@code -2} is the second + * to last day, and so on. + */ + final byte dom; + /** + * The cutover day-of-week, -1 to retain the day-of-month. + */ + final int dow; + /** + * The cutover time in the 'before' offset. + */ + final LocalTime time; + /** + * Whether the cutover time is midnight at the end of day. + */ + final boolean timeEndOfDay; + /** + * The definition of how the local time should be interpreted. + */ + final TimeDefinition timeDefinition; + /** + * The standard offset at the cutover. + */ + final ZoneOffset standardOffset; + /** + * The offset before the cutover. + */ + final ZoneOffset offsetBefore; + /** + * The offset after the cutover. + */ + final ZoneOffset offsetAfter; + + /** + * Creates an instance defining the yearly rule to create transitions between two offsets. + * + * @param month the month of the month-day of the first day of the cutover week, from 1 to 12 + * @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that + * day or later, negative if the week is that day or earlier, counting from the last day of the month, + * from -28 to 31 excluding 0 + * @param dayOfWeek the required day-of-week, -1 if the month-day should not be changed + * @param time the cutover time in the 'before' offset, not null + * @param timeEndOfDay whether the time is midnight at the end of day + * @param timeDefnition how to interpret the cutover + * @param standardOffset the standard offset in force at the cutover, not null + * @param offsetBefore the offset before the cutover, not null + * @param offsetAfter the offset after the cutover, not null + * @throws IllegalArgumentException if the day of month indicator is invalid + * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight + */ + ZoneOffsetTransitionRule( + int month, + int dayOfMonthIndicator, + int dayOfWeek, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefnition, + ZoneOffset standardOffset, + ZoneOffset offsetBefore, + ZoneOffset offsetAfter) { + Objects.requireNonNull(time, "time"); + Objects.requireNonNull(timeDefnition, "timeDefnition"); + Objects.requireNonNull(standardOffset, "standardOffset"); + Objects.requireNonNull(offsetBefore, "offsetBefore"); + Objects.requireNonNull(offsetAfter, "offsetAfter"); + if (month < 1 || month > 12) { + throw new IllegalArgumentException("month must be between 1 and 12"); + } + if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) { + throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero"); + } + if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) { + throw new IllegalArgumentException("Time must be midnight when end of day flag is true"); + } + this.month = month; + this.dom = (byte) dayOfMonthIndicator; + this.dow = dayOfWeek; + this.time = time; + this.timeEndOfDay = timeEndOfDay; + this.timeDefinition = timeDefnition; + this.standardOffset = standardOffset; + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + //----------------------------------------------------------------------- + /** + * Checks if this object equals another. + *

+ * The entire state of the object is compared. + * + * @param otherRule the other object to compare to, null returns false + * @return true if equal + */ + @Override + public boolean equals(Object otherRule) { + if (otherRule == this) { + return true; + } + if (otherRule instanceof ZoneOffsetTransitionRule) { + ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule; + return month == other.month && dom == other.dom && dow == other.dow && + timeDefinition == other.timeDefinition && + time.equals(other.time) && + timeEndOfDay == other.timeEndOfDay && + standardOffset.equals(other.standardOffset) && + offsetBefore.equals(other.offsetBefore) && + offsetAfter.equals(other.offsetAfter); + } + return false; + } + + /** + * Returns a suitable hash code. + * + * @return the hash code + */ + @Override + public int hashCode() { + int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) + + (month << 11) + ((dom + 32) << 5) + + ((dow == -1 ? 8 : dow) << 2) + (timeDefinition.ordinal()); + return hash ^ standardOffset.hashCode() ^ + offsetBefore.hashCode() ^ offsetAfter.hashCode(); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/ZoneRules.java b/jdk/make/tools/src/build/tools/tzdb/ZoneRules.java new file mode 100644 index 00000000000..22c3be80c02 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ZoneRules.java @@ -0,0 +1,311 @@ +/* + * 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. + */ + +/* + * 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) 2011-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 build.tools.tzdb; + +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; + +/** + * Duplicated code of javax.time.zone.ZoneRules, ZoneOffsetTransitionRule + * and Ser to generate the serialization form output of ZoneRules for + * tzdb.jar. + * + * Implementation here is the copy/paste of ZoneRules, ZoneOffsetTransitionRule + * and Ser in javax.time.zone package. Make sure the code here is synchrionozed + * with the serialization implementation there. + * + * @since 1.8 + */ + +final class ZoneRules { + + /** + * The transitions between standard offsets (epoch seconds), sorted. + */ + private final long[] standardTransitions; + /** + * The standard offsets. + */ + private final ZoneOffset[] standardOffsets; + /** + * The transitions between instants (epoch seconds), sorted. + */ + private final long[] savingsInstantTransitions; + + /** + * The wall offsets. + */ + private final ZoneOffset[] wallOffsets; + /** + * The last rule. + */ + private final ZoneOffsetTransitionRule[] lastRules; + + /** + * Creates an instance. + * + * @param baseStandardOffset the standard offset to use before legal rules were set, not null + * @param baseWallOffset the wall offset to use before legal rules were set, not null + * @param standardOffsetTransitionList the list of changes to the standard offset, not null + * @param transitionList the list of transitions, not null + * @param lastRules the recurring last rules, size 16 or less, not null + */ + ZoneRules(ZoneOffset baseStandardOffset, + ZoneOffset baseWallOffset, + List standardOffsetTransitionList, + List transitionList, + List lastRules) { + + this.standardTransitions = new long[standardOffsetTransitionList.size()]; + + this.standardOffsets = new ZoneOffset[standardOffsetTransitionList.size() + 1]; + this.standardOffsets[0] = baseStandardOffset; + for (int i = 0; i < standardOffsetTransitionList.size(); i++) { + this.standardTransitions[i] = standardOffsetTransitionList.get(i).toEpochSecond(); + this.standardOffsets[i + 1] = standardOffsetTransitionList.get(i).getOffsetAfter(); + } + + // convert savings transitions to locals + List localTransitionOffsetList = new ArrayList<>(); + localTransitionOffsetList.add(baseWallOffset); + for (ZoneOffsetTransition trans : transitionList) { + localTransitionOffsetList.add(trans.getOffsetAfter()); + } + + this.wallOffsets = localTransitionOffsetList.toArray(new ZoneOffset[localTransitionOffsetList.size()]); + + // convert savings transitions to instants + this.savingsInstantTransitions = new long[transitionList.size()]; + for (int i = 0; i < transitionList.size(); i++) { + this.savingsInstantTransitions[i] = transitionList.get(i).toEpochSecond(); + } + + // last rules + if (lastRules.size() > 16) { + throw new IllegalArgumentException("Too many transition rules"); + } + this.lastRules = lastRules.toArray(new ZoneOffsetTransitionRule[lastRules.size()]); + } + + /** Type for ZoneRules. */ + static final byte ZRULES = 1; + + /** + * Writes the state to the stream. + * + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + void writeExternal(DataOutput out) throws IOException { + out.writeByte(ZRULES); + out.writeInt(standardTransitions.length); + for (long trans : standardTransitions) { + writeEpochSec(trans, out); + } + for (ZoneOffset offset : standardOffsets) { + writeOffset(offset, out); + } + out.writeInt(savingsInstantTransitions.length); + for (long trans : savingsInstantTransitions) { + writeEpochSec(trans, out); + } + for (ZoneOffset offset : wallOffsets) { + writeOffset(offset, out); + } + out.writeByte(lastRules.length); + for (ZoneOffsetTransitionRule rule : lastRules) { + writeRule(rule, out); + } + } + + /** + * Writes the state the ZoneOffset to the stream. + * + * @param offset the offset, not null + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException { + final int offsetSecs = offset.getTotalSeconds(); + int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127; // compress to -72 to +72 + out.writeByte(offsetByte); + if (offsetByte == 127) { + out.writeInt(offsetSecs); + } + } + + /** + * Writes the epoch seconds to the stream. + * + * @param epochSec the epoch seconds, not null + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + static void writeEpochSec(long epochSec, DataOutput out) throws IOException { + if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) { // quarter hours between 1825 and 2300 + int store = (int) ((epochSec + 4575744000L) / 900); + out.writeByte((store >>> 16) & 255); + out.writeByte((store >>> 8) & 255); + out.writeByte(store & 255); + } else { + out.writeByte(255); + out.writeLong(epochSec); + } + } + + /** + * Writes the state of the transition rule to the stream. + * + * @param rule the transition rule, not null + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + static void writeRule(ZoneOffsetTransitionRule rule, DataOutput out) throws IOException { + int month = rule.month; + byte dom = rule.dom; + int dow = rule.dow; + LocalTime time = rule.time; + boolean timeEndOfDay = rule.timeEndOfDay; + TimeDefinition timeDefinition = rule.timeDefinition; + ZoneOffset standardOffset = rule.standardOffset; + ZoneOffset offsetBefore = rule.offsetBefore; + ZoneOffset offsetAfter = rule.offsetAfter; + + int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay()); + int stdOffset = standardOffset.getTotalSeconds(); + int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset; + int afterDiff = offsetAfter.getTotalSeconds() - stdOffset; + int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31); + int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255); + int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3); + int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3); + int dowByte = (dow == -1 ? 0 : dow); + int b = (month << 28) + // 4 bytes + ((dom + 32) << 22) + // 6 bytes + (dowByte << 19) + // 3 bytes + (timeByte << 14) + // 5 bytes + (timeDefinition.ordinal() << 12) + // 2 bytes + (stdOffsetByte << 4) + // 8 bytes + (beforeByte << 2) + // 2 bytes + afterByte; // 2 bytes + out.writeInt(b); + if (timeByte == 31) { + out.writeInt(timeSecs); + } + if (stdOffsetByte == 255) { + out.writeInt(stdOffset); + } + if (beforeByte == 3) { + out.writeInt(offsetBefore.getTotalSeconds()); + } + if (afterByte == 3) { + out.writeInt(offsetAfter.getTotalSeconds()); + } + } + + /** + * Checks if this set of rules equals another. + *

+ * Two rule sets are equal if they will always result in the same output + * for any given input instant or local date-time. + * Rules from two different groups may return false even if they are in fact the same. + *

+ * This definition should result in implementations comparing their entire state. + * + * @param otherRules the other rules, null returns false + * @return true if this rules is the same as that specified + */ + @Override + public boolean equals(Object otherRules) { + if (this == otherRules) { + return true; + } + if (otherRules instanceof ZoneRules) { + ZoneRules other = (ZoneRules) otherRules; + return Arrays.equals(standardTransitions, other.standardTransitions) && + Arrays.equals(standardOffsets, other.standardOffsets) && + Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) && + Arrays.equals(wallOffsets, other.wallOffsets) && + Arrays.equals(lastRules, other.lastRules); + } + return false; + } + + /** + * Returns a suitable hash code given the definition of {@code #equals}. + * + * @return the hash code + */ + @Override + public int hashCode() { + return Arrays.hashCode(standardTransitions) ^ + Arrays.hashCode(standardOffsets) ^ + Arrays.hashCode(savingsInstantTransitions) ^ + Arrays.hashCode(wallOffsets) ^ + Arrays.hashCode(lastRules); + } + +} diff --git a/jdk/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java b/jdk/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java new file mode 100644 index 00000000000..f4a437dc074 --- /dev/null +++ b/jdk/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java @@ -0,0 +1,743 @@ +/* + * 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. + */ + +/* + * 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 build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A mutable builder used to create all the rules for a historic time-zone. + *

+ * The rules of a time-zone describe how the offset changes over time. + * The rules are created by building windows on the time-line within which + * the different rules apply. The rules may be one of two kinds: + *

    + *
  • Fixed savings - A single fixed amount of savings from the standard offset will apply.
  • + *
  • Rules - A set of one or more rules describe how daylight savings changes during the window.
  • + *

+ * + *

Implementation notes

+ * This class is a mutable builder used to create zone instances. + * It must only be used from a single thread. + * The created instances are immutable and thread-safe. + * + * @since 1.8 + */ +public class ZoneRulesBuilder { + + /** + * The list of windows. + */ + private List windowList = new ArrayList<>(); + + //----------------------------------------------------------------------- + /** + * Constructs an instance of the builder that can be used to create zone rules. + *

+ * The builder is used by adding one or more windows representing portions + * of the time-line. The standard offset from UTC/Greenwich will be constant + * within a window, although two adjacent windows can have the same standard offset. + *

+ * Within each window, there can either be a + * {@link #setFixedSavingsToWindow fixed savings amount} or a + * {@link #addRuleToWindow list of rules}. + */ + public ZoneRulesBuilder() { + } + + //----------------------------------------------------------------------- + /** + * Adds a window to the builder that can be used to filter a set of rules. + *

+ * This method defines and adds a window to the zone where the standard offset is specified. + * The window limits the effect of subsequent additions of transition rules + * or fixed savings. If neither rules or fixed savings are added to the window + * then the window will default to no savings. + *

+ * Each window must be added sequentially, as the start instant of the window + * is derived from the until instant of the previous window. + * + * @param standardOffset the standard offset, not null + * @param until the date-time that the offset applies until, not null + * @param untilDefinition the time type for the until date-time, not null + * @return this, for chaining + * @throws IllegalStateException if the window order is invalid + */ + public ZoneRulesBuilder addWindow( + ZoneOffset standardOffset, + LocalDateTime until, + TimeDefinition untilDefinition) { + Objects.requireNonNull(standardOffset, "standardOffset"); + Objects.requireNonNull(until, "until"); + Objects.requireNonNull(untilDefinition, "untilDefinition"); + TZWindow window = new TZWindow(standardOffset, until, untilDefinition); + if (windowList.size() > 0) { + TZWindow previous = windowList.get(windowList.size() - 1); + window.validateWindowOrder(previous); + } + windowList.add(window); + return this; + } + + /** + * Adds a window that applies until the end of time to the builder that can be + * used to filter a set of rules. + *

+ * This method defines and adds a window to the zone where the standard offset is specified. + * The window limits the effect of subsequent additions of transition rules + * or fixed savings. If neither rules or fixed savings are added to the window + * then the window will default to no savings. + *

+ * This must be added after all other windows. + * No more windows can be added after this one. + * + * @param standardOffset the standard offset, not null + * @return this, for chaining + * @throws IllegalStateException if a forever window has already been added + */ + public ZoneRulesBuilder addWindowForever(ZoneOffset standardOffset) { + return addWindow(standardOffset, LocalDateTime.MAX, TimeDefinition.WALL); + } + + //----------------------------------------------------------------------- + /** + * Sets the previously added window to have fixed savings. + *

+ * Setting a window to have fixed savings simply means that a single daylight + * savings amount applies throughout the window. The window could be small, + * such as a single summer, or large, such as a multi-year daylight savings. + *

+ * A window can either have fixed savings or rules but not both. + * + * @param fixedSavingAmountSecs the amount of saving to use for the whole window, not null + * @return this, for chaining + * @throws IllegalStateException if no window has yet been added + * @throws IllegalStateException if the window already has rules + */ + public ZoneRulesBuilder setFixedSavingsToWindow(int fixedSavingAmountSecs) { + if (windowList.isEmpty()) { + throw new IllegalStateException("Must add a window before setting the fixed savings"); + } + TZWindow window = windowList.get(windowList.size() - 1); + window.setFixedSavings(fixedSavingAmountSecs); + return this; + } + + //----------------------------------------------------------------------- + /** + * Adds a single transition rule to the current window. + *

+ * This adds a rule such that the offset, expressed as a daylight savings amount, + * changes at the specified date-time. + * + * @param transitionDateTime the date-time that the transition occurs as defined by timeDefintion, not null + * @param timeDefinition the definition of how to convert local to actual time, not null + * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds + * @return this, for chaining + * @throws IllegalStateException if no window has yet been added + * @throws IllegalStateException if the window already has fixed savings + * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules + */ + public ZoneRulesBuilder addRuleToWindow( + LocalDateTime transitionDateTime, + TimeDefinition timeDefinition, + int savingAmountSecs) { + Objects.requireNonNull(transitionDateTime, "transitionDateTime"); + return addRuleToWindow( + transitionDateTime.getYear(), transitionDateTime.getYear(), + transitionDateTime.getMonth(), transitionDateTime.getDayOfMonth(), + -1, transitionDateTime.getTime(), false, timeDefinition, savingAmountSecs); + } + + /** + * Adds a single transition rule to the current window. + *

+ * This adds a rule such that the offset, expressed as a daylight savings amount, + * changes at the specified date-time. + * + * @param year the year of the transition, from MIN_YEAR to MAX_YEAR + * @param month the month of the transition, not null + * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek, + * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month + * @param time the time that the transition occurs as defined by timeDefintion, not null + * @param timeEndOfDay whether midnight is at the end of day + * @param timeDefinition the definition of how to convert local to actual time, not null + * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds + * @return this, for chaining + * @throws DateTimeException if a date-time field is out of range + * @throws IllegalStateException if no window has yet been added + * @throws IllegalStateException if the window already has fixed savings + * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules + */ + public ZoneRulesBuilder addRuleToWindow( + int year, + int month, + int dayOfMonthIndicator, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefinition, + int savingAmountSecs) { + return addRuleToWindow(year, year, month, dayOfMonthIndicator, -1, time, timeEndOfDay, timeDefinition, savingAmountSecs); + } + + /** + * Adds a multi-year transition rule to the current window. + *

+ * This adds a rule such that the offset, expressed as a daylight savings amount, + * changes at the specified date-time for each year in the range. + * + * @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR + * @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR + * @param month the month of the transition, from 1 to 12 + * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek, + * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month + * @param dayOfWeek the day-of-week to adjust to, -1 if day-of-month should not be adjusted + * @param time the time that the transition occurs as defined by timeDefintion, not null + * @param timeEndOfDay whether midnight is at the end of day + * @param timeDefinition the definition of how to convert local to actual time, not null + * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds + * @return this, for chaining + * @throws DateTimeException if a date-time field is out of range + * @throws IllegalArgumentException if the day of month indicator is invalid + * @throws IllegalArgumentException if the end of day midnight flag does not match the time + * @throws IllegalStateException if no window has yet been added + * @throws IllegalStateException if the window already has fixed savings + * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules + */ + public ZoneRulesBuilder addRuleToWindow( + int startYear, + int endYear, + int month, + int dayOfMonthIndicator, + int dayOfWeek, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefinition, + int savingAmountSecs) { + Objects.requireNonNull(time, "time"); + Objects.requireNonNull(timeDefinition, "timeDefinition"); + if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) { + throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero"); + } + if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) { + throw new IllegalArgumentException("Time must be midnight when end of day flag is true"); + } + if (windowList.isEmpty()) { + throw new IllegalStateException("Must add a window before adding a rule"); + } + TZWindow window = windowList.get(windowList.size() - 1); + window.addRule(startYear, endYear, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs); + return this; + } + + //----------------------------------------------------------------------- + /** + * Completes the build converting the builder to a set of time-zone rules. + *

+ * Calling this method alters the state of the builder. + * Further rules should not be added to this builder once this method is called. + * + * @param zoneId the time-zone ID, not null + * @return the zone rules, not null + * @throws IllegalStateException if no windows have been added + * @throws IllegalStateException if there is only one rule defined as being forever for any given window + */ + public ZoneRules toRules(String zoneId) { + Objects.requireNonNull(zoneId, "zoneId"); + if (windowList.isEmpty()) { + throw new IllegalStateException("No windows have been added to the builder"); + } + + final List standardTransitionList = new ArrayList<>(4); + final List transitionList = new ArrayList<>(256); + final List lastTransitionRuleList = new ArrayList<>(2); + + // initialize the standard offset calculation + final TZWindow firstWindow = windowList.get(0); + ZoneOffset loopStandardOffset = firstWindow.standardOffset; + int loopSavings = 0; + if (firstWindow.fixedSavingAmountSecs != null) { + loopSavings = firstWindow.fixedSavingAmountSecs; + } + final ZoneOffset firstWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + loopSavings); + LocalDateTime loopWindowStart = LocalDateTime.of(YEAR_MIN_VALUE, 1, 1, 0, 0); + ZoneOffset loopWindowOffset = firstWallOffset; + + // build the windows and rules to interesting data + for (TZWindow window : windowList) { + // tidy the state + window.tidy(loopWindowStart.getYear()); + + // calculate effective savings at the start of the window + Integer effectiveSavings = window.fixedSavingAmountSecs; + if (effectiveSavings == null) { + // apply rules from this window together with the standard offset and + // savings from the last window to find the savings amount applicable + // at start of this window + effectiveSavings = 0; + for (TZRule rule : window.ruleList) { + if (rule.toEpochSecond(loopStandardOffset, loopSavings) > loopWindowStart.toEpochSecond(loopWindowOffset)) { + // previous savings amount found, which could be the savings amount at + // the instant that the window starts (hence isAfter) + break; + } + effectiveSavings = rule.savingAmountSecs; + } + } + + // check if standard offset changed, and update it + if (loopStandardOffset.equals(window.standardOffset) == false) { + standardTransitionList.add( + new ZoneOffsetTransition( + LocalDateTime.ofEpochSecond(loopWindowStart.toEpochSecond(loopWindowOffset), 0, loopStandardOffset), + loopStandardOffset, window.standardOffset)); + loopStandardOffset = window.standardOffset; + } + + // check if the start of the window represents a transition + ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + effectiveSavings); + if (loopWindowOffset.equals(effectiveWallOffset) == false) { + transitionList.add(new ZoneOffsetTransition(loopWindowStart, loopWindowOffset, effectiveWallOffset)); + } + loopSavings = effectiveSavings; + + // apply rules within the window + for (TZRule rule : window.ruleList) { + if (rule.isTransition(loopSavings)) { + ZoneOffsetTransition trans = rule.toTransition(loopStandardOffset, loopSavings); + if (trans.toEpochSecond() < loopWindowStart.toEpochSecond(loopWindowOffset) == false && + trans.toEpochSecond() < window.createDateTimeEpochSecond(loopSavings)) { + transitionList.add(trans); + loopSavings = rule.savingAmountSecs; + } + } + } + + // calculate last rules + for (TZRule lastRule : window.lastRuleList) { + lastTransitionRuleList.add(lastRule.toTransitionRule(loopStandardOffset, loopSavings)); + loopSavings = lastRule.savingAmountSecs; + } + + // finally we can calculate the true end of the window, passing it to the next window + loopWindowOffset = window.createWallOffset(loopSavings); + loopWindowStart = LocalDateTime.ofEpochSecond( + window.createDateTimeEpochSecond(loopSavings), 0, loopWindowOffset); + } + + return new ZoneRules( + firstWindow.standardOffset, firstWallOffset, standardTransitionList, + transitionList, lastTransitionRuleList); + } + + //----------------------------------------------------------------------- + /** + * A definition of a window in the time-line. + * The window will have one standard offset and will either have a + * fixed DST savings or a set of rules. + */ + class TZWindow { + /** The standard offset during the window, not null. */ + private final ZoneOffset standardOffset; + /** The end local time, not null. */ + private final LocalDateTime windowEnd; + /** The type of the end time, not null. */ + private final TimeDefinition timeDefinition; + + /** The fixed amount of the saving to be applied during this window. */ + private Integer fixedSavingAmountSecs; + /** The rules for the current window. */ + private List ruleList = new ArrayList<>(); + /** The latest year that the last year starts at. */ + private int maxLastRuleStartYear = YEAR_MIN_VALUE; + /** The last rules. */ + private List lastRuleList = new ArrayList<>(); + + /** + * Constructor. + * + * @param standardOffset the standard offset applicable during the window, not null + * @param windowEnd the end of the window, relative to the time definition, null if forever + * @param timeDefinition the time definition for calculating the true end, not null + */ + TZWindow( + ZoneOffset standardOffset, + LocalDateTime windowEnd, + TimeDefinition timeDefinition) { + super(); + this.windowEnd = windowEnd; + this.timeDefinition = timeDefinition; + this.standardOffset = standardOffset; + } + + /** + * Sets the fixed savings amount for the window. + * + * @param fixedSavingAmount the amount of daylight saving to apply throughout the window, may be null + * @throws IllegalStateException if the window already has rules + */ + void setFixedSavings(int fixedSavingAmount) { + if (ruleList.size() > 0 || lastRuleList.size() > 0) { + throw new IllegalStateException("Window has DST rules, so cannot have fixed savings"); + } + this.fixedSavingAmountSecs = fixedSavingAmount; + } + + /** + * Adds a rule to the current window. + * + * @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR + * @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR + * @param month the month of the transition, not null + * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek, + * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month + * @param dayOfWeek the day-of-week to adjust to, null if day-of-month should not be adjusted + * @param time the time that the transition occurs as defined by timeDefintion, not null + * @param timeEndOfDay whether midnight is at the end of day + * @param timeDefinition the definition of how to convert local to actual time, not null + * @param savingAmountSecs the amount of saving from the standard offset in seconds + * @throws IllegalStateException if the window already has fixed savings + * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules + */ + void addRule( + int startYear, + int endYear, + int month, + int dayOfMonthIndicator, + int dayOfWeek, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefinition, + int savingAmountSecs) { + + if (fixedSavingAmountSecs != null) { + throw new IllegalStateException("Window has a fixed DST saving, so cannot have DST rules"); + } + if (ruleList.size() >= 2000) { + throw new IllegalStateException("Window has reached the maximum number of allowed rules"); + } + boolean lastRule = false; + if (endYear == YEAR_MAX_VALUE) { + lastRule = true; + endYear = startYear; + } + int year = startYear; + while (year <= endYear) { + TZRule rule = new TZRule(year, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs); + if (lastRule) { + lastRuleList.add(rule); + maxLastRuleStartYear = Math.max(startYear, maxLastRuleStartYear); + } else { + ruleList.add(rule); + } + year++; + } + } + + /** + * Validates that this window is after the previous one. + * + * @param previous the previous window, not null + * @throws IllegalStateException if the window order is invalid + */ + void validateWindowOrder(TZWindow previous) { + if (windowEnd.compareTo(previous.windowEnd) < 0) { + throw new IllegalStateException("Windows must be added in date-time order: " + + windowEnd + " < " + previous.windowEnd); + } + } + + /** + * Adds rules to make the last rules all start from the same year. + * Also add one more year to avoid weird case where penultimate year has odd offset. + * + * @param windowStartYear the window start year + * @throws IllegalStateException if there is only one rule defined as being forever + */ + void tidy(int windowStartYear) { + if (lastRuleList.size() == 1) { + throw new IllegalStateException("Cannot have only one rule defined as being forever"); + } + + // handle last rules + if (windowEnd.equals(LocalDateTime.MAX)) { + // setup at least one real rule, which closes off other windows nicely + maxLastRuleStartYear = Math.max(maxLastRuleStartYear, windowStartYear) + 1; + for (TZRule lastRule : lastRuleList) { + addRule(lastRule.year, maxLastRuleStartYear, lastRule.month, lastRule.dayOfMonthIndicator, + lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs); + lastRule.year = maxLastRuleStartYear + 1; + } + if (maxLastRuleStartYear == YEAR_MAX_VALUE) { + lastRuleList.clear(); + } else { + maxLastRuleStartYear++; + } + } else { + // convert all within the endYear limit + int endYear = windowEnd.getYear(); + for (TZRule lastRule : lastRuleList) { + addRule(lastRule.year, endYear + 1, lastRule.month, lastRule.dayOfMonthIndicator, + lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs); + } + lastRuleList.clear(); + maxLastRuleStartYear = YEAR_MAX_VALUE; + } + + // ensure lists are sorted + Collections.sort(ruleList); + Collections.sort(lastRuleList); + + // default fixed savings to zero + if (ruleList.size() == 0 && fixedSavingAmountSecs == null) { + fixedSavingAmountSecs = 0; + } + } + + /** + * Checks if the window is empty. + * + * @return true if the window is only a standard offset + */ + boolean isSingleWindowStandardOffset() { + return windowEnd.equals(LocalDateTime.MAX) && timeDefinition == TimeDefinition.WALL && + fixedSavingAmountSecs == null && lastRuleList.isEmpty() && ruleList.isEmpty(); + } + + /** + * Creates the wall offset for the local date-time at the end of the window. + * + * @param savingsSecs the amount of savings in use in seconds + * @return the created date-time epoch second in the wall offset, not null + */ + ZoneOffset createWallOffset(int savingsSecs) { + return ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsSecs); + } + + /** + * Creates the offset date-time for the local date-time at the end of the window. + * + * @param savingsSecs the amount of savings in use in seconds + * @return the created date-time epoch second in the wall offset, not null + */ + long createDateTimeEpochSecond(int savingsSecs) { + ZoneOffset wallOffset = createWallOffset(savingsSecs); + LocalDateTime ldt = timeDefinition.createDateTime(windowEnd, standardOffset, wallOffset); + return ldt.toEpochSecond(wallOffset); + } + } + + //----------------------------------------------------------------------- + /** + * A definition of the way a local time can be converted to an offset time. + */ + class TZRule implements Comparable { + private int year; + private int month; + private int dayOfMonthIndicator; + private int dayOfWeek; + private LocalTime time; + private boolean timeEndOfDay; // Whether the local time is end of day. + private TimeDefinition timeDefinition; // The type of the time. + private int savingAmountSecs; // The amount of the saving to be applied after this point. + + /** + * Constructor. + * + * @param year the year + * @param month the month, value from 1 to 12 + * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek, + * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month + * @param dayOfWeek the day-of-week, -1 if day-of-month is exact + * @param time the time, not null + * @param timeEndOfDay whether midnight is at the end of day + * @param timeDefinition the time definition, not null + * @param savingAfterSecs the savings amount in seconds + */ + TZRule(int year, int month, int dayOfMonthIndicator, + int dayOfWeek, LocalTime time, boolean timeEndOfDay, + TimeDefinition timeDefinition, int savingAfterSecs) { + this.year = year; + this.month = month; + this.dayOfMonthIndicator = dayOfMonthIndicator; + this.dayOfWeek = dayOfWeek; + this.time = time; + this.timeEndOfDay = timeEndOfDay; + this.timeDefinition = timeDefinition; + this.savingAmountSecs = savingAfterSecs; + } + + /** + * Converts this to a transition. + * + * @param standardOffset the active standard offset, not null + * @param savingsBeforeSecs the active savings in seconds + * @return the transition, not null + */ + ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) { + // copy of code in ZoneOffsetTransitionRule to avoid infinite loop + LocalDate date = toLocalDate(); + LocalDateTime ldt = LocalDateTime.of(date, time); + ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs); + LocalDateTime dt = timeDefinition.createDateTime(ldt, standardOffset, wallOffset); + ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs); + return new ZoneOffsetTransition(dt, wallOffset, offsetAfter); + } + + /** + * Returns the apoch second of this rules with the specified + * active standard offset and active savings + * + * @param standardOffset the active standard offset, not null + * @param savingsBeforeSecs the active savings in seconds + * @return the transition epoch second + */ + long toEpochSecond(ZoneOffset standardOffset, int savingsBeforeSecs) { + LocalDateTime ldt = LocalDateTime.of(toLocalDate(), time); + ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs); + return timeDefinition.createDateTime(ldt, standardOffset, wallOffset) + .toEpochSecond(wallOffset); + } + + /** + * Tests if this a real transition with the active savings in seconds + * + * @param savingsBeforeSecs the active savings in seconds + * @return true, if savings in seconds changes + */ + boolean isTransition(int savingsBeforeSecs) { + return savingAmountSecs != savingsBeforeSecs; + } + + /** + * Converts this to a transition rule. + * + * @param standardOffset the active standard offset, not null + * @param savingsBeforeSecs the active savings before the transition in seconds + * @return the transition, not null + */ + ZoneOffsetTransitionRule toTransitionRule(ZoneOffset standardOffset, int savingsBeforeSecs) { + // optimize stored format + if (dayOfMonthIndicator < 0) { + if (month != 2) { // not Month.FEBRUARY + dayOfMonthIndicator = maxLengthOfMonth(month) - 6; + } + } + if (timeEndOfDay && dayOfMonthIndicator > 0 && + (dayOfMonthIndicator == 28 && month == 2) == false) { + LocalDate date = LocalDate.of(2004, month, dayOfMonthIndicator).plusDays(1); // leap-year + month = date.getMonth(); + dayOfMonthIndicator = date.getDayOfMonth(); + if (dayOfWeek != -1) { + dayOfWeek = plusDayOfWeek(dayOfWeek, 1); + } + timeEndOfDay = false; + } + // build rule + return new ZoneOffsetTransitionRule( + month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, + standardOffset, + ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs), + ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs)); + } + + public int compareTo(TZRule other) { + int cmp = year - other.year; + cmp = (cmp == 0 ? month - other.month : cmp); + if (cmp == 0) { + // convert to date to handle dow/domIndicator/timeEndOfDay + LocalDate thisDate = toLocalDate(); + LocalDate otherDate = other.toLocalDate(); + cmp = thisDate.compareTo(otherDate); + } + cmp = (cmp == 0 ? time.compareTo(other.time) : cmp); + return cmp; + } + + private LocalDate toLocalDate() { + LocalDate date; + if (dayOfMonthIndicator < 0) { + int monthLen = lengthOfMonth(month, isLeapYear(year)); + date = LocalDate.of(year, month, monthLen + 1 + dayOfMonthIndicator); + if (dayOfWeek != -1) { + date = previousOrSame(date, dayOfWeek); + } + } else { + date = LocalDate.of(year, month, dayOfMonthIndicator); + if (dayOfWeek != -1) { + date = nextOrSame(date, dayOfWeek); + } + } + if (timeEndOfDay) { + date = date.plusDays(1); + } + return date; + } + } + +} diff --git a/jdk/make/tools/tzdb/Makefile b/jdk/make/tools/tzdb/Makefile new file mode 100644 index 00000000000..895a0e8cfb0 --- /dev/null +++ b/jdk/make/tools/tzdb/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 1998, 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. +# + +# +# Makefile for building the tzdb compiler tool +# + +BUILDDIR = ../.. +PACKAGE = build.tools.tzdb +PRODUCT = tzdb +PROGRAM = tzdb +include $(BUILDDIR)/common/Defs.gmk + +BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src +BUILDTOOL_MAIN = $(PKGDIR)/TzdbZoneRulesCompiler.java + +# +# Build tool jar rules. +# +include $(BUILDDIR)/common/BuildToolJar.gmk + diff --git a/jdk/makefiles/CompileJavaClasses.gmk b/jdk/makefiles/CompileJavaClasses.gmk index abcbbfb9ffb..584458c00c4 100644 --- a/jdk/makefiles/CompileJavaClasses.gmk +++ b/jdk/makefiles/CompileJavaClasses.gmk @@ -59,6 +59,12 @@ ifndef OPENJDK # This gets built on unix platforms implicitly in the old build even though # it's excluded in the closed build. EXCLUDES+=sun/java2d/pisces + + # AccessBridge is compiled separately below. + EXFILES += AccessBridge.java \ + com/sun/java/accessibility/util/java/awt/ChoiceTranslator.java + # This seems to never be built + EXCLUDES += com/sun/java/accessibility/extensions endif endif @@ -248,10 +254,8 @@ include CopyIntoClasses.gmk # Now we have COPY_PATTERNS, COPY_FILES and COPY_EXTRA ifndef OPENJDK - CLOSED_SRC_DIRS:=$(JDK_TOPDIR)/src/closed/share/classes - ifneq ($(OPENJDK_TARGET_OS_API_DIR),windows) - CLOSED_SRC_DIRS += $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes - endif + CLOSED_SRC_DIRS:=$(JDK_TOPDIR)/src/closed/share/classes \ + $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes endif MACOSX_SRC_DIRS := @@ -364,8 +368,44 @@ endif ########################################################################################## -# copy with -a to preserve timestamps so dependencies down the line aren't messed up +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS), windows) +ifeq ($(OPENJDK_TARGET_CPU_BITS), 32) + $(eval $(call SetupJavaCompilation,BUILD_ACCESSBRIDGE_32,\ + SETUP:=GENERATE_JDKBYTECODE,\ + JAVAC_FLAGS:=-cp $(JDK_OUTPUTDIR)/classes,\ + SRC:=$(JDK_OUTPUTDIR)/gensrc_ab/32bit,\ + BIN:=$(JDK_OUTPUTDIR)/classes_ab/32bit)) + + $(BUILD_ACCESSBRIDGE_32): $(BUILD_JDK) + + $(eval $(call SetupJavaCompilation,BUILD_ACCESSBRIDGE_LEGACY,\ + SETUP:=GENERATE_JDKBYTECODE,\ + JAVAC_FLAGS:=-cp $(JDK_OUTPUTDIR)/classes,\ + SRC:=$(JDK_OUTPUTDIR)/gensrc_ab/legacy,\ + BIN:=$(JDK_OUTPUTDIR)/classes_ab/legacy)) + + $(BUILD_ACCESSBRIDGE_LEGACY): $(BUILD_JDK) + +else + + $(eval $(call SetupJavaCompilation,BUILD_ACCESSBRIDGE_64,\ + SETUP:=GENERATE_JDKBYTECODE,\ + JAVAC_FLAGS:=-cp $(JDK_OUTPUTDIR)/classes,\ + SRC:=$(JDK_OUTPUTDIR)/gensrc_ab/64bit,\ + BIN:=$(JDK_OUTPUTDIR)/classes_ab/64bit)) + + $(BUILD_ACCESSBRIDGE_64): $(BUILD_JDK) + +endif +endif +endif + +########################################################################################## + all: $(BUILD_JDK) $(BUILD_ALTCLASSES) $(BUILD_JOBJC) $(BUILD_JOBJC_HEADERS) $(COPY_EXTRA) \ - $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin + $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin \ + $(BUILD_ACCESSBRIDGE_32) $(BUILD_ACCESSBRIDGE_64) \ + $(BUILD_ACCESSBRIDGE_LEGACY) .PHONY: all diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk index 354fea12044..170dc164ec4 100644 --- a/jdk/makefiles/CompileLaunchers.gmk +++ b/jdk/makefiles/CompileLaunchers.gmk @@ -590,6 +590,34 @@ else $(CHMOD) a+x $@ endif +########################################################################################## +# jabswitch + +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS),windows) + + $(eval $(call SetupNativeCompilation,BUILD_JABSWITCH,\ + SRC:=$(JDK_TOPDIR)/src/closed/windows/native/sun/bridge,\ + INCLUDE_FILES:=jabswitch.cpp,\ + LANG:=C++,\ + CFLAGS:=$(filter-out -Zc:wchar_t-,$(CFLAGS_JDKEXE)) -Zc:wchar_t \ + -analyze- -Od -Gd -D_WINDOWS \ + -D_UNICODE -DUNICODE -RTC1 -EHsc,\ + LDFLAGS:=$(LDFLAGS_JDKEXE) \ + Advapi32.lib Version.lib User32.lib,\ + OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/jabswitch,\ + OUTPUT_DIR:=$(JDK_OUTPUTDIR)/bin,\ + PROGRAM:=jabswitch,\ + DEBUG_SYMBOLS:=true,\ + VERSIONINFO_RESOURCE:=$(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/AccessBridgeStatusWindow.rc,\ + RC_FLAGS:=$(RC_FLAGS),\ + MANIFEST:=$(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/jabswitch.manifest)) + + BUILD_LAUNCHERS += $(BUILD_JABSWITCH) + +endif +endif + ########################################################################################## $(BUILD_LAUNCHERS) : $(JDK_TOPDIR)/makefiles/CompileLaunchers.gmk diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 5d601c66156..fdd2762107d 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -3294,6 +3294,97 @@ BUILD_LIBRARIES += $(INSTALL_LIBRARIES_HERE)/$(LIBRARY_PREFIX)JObjC$(SHARED_LIBR endif +########################################################################################## + +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS), windows) + + ACCESSBRIDGE_SRCDIR:=$(JDK_TOPDIR)/src/closed/windows/native/sun/bridge + + define SetupAccessBridge + # Parameter 1 Suffix + # Parameter 2 Machine + # Parameter 3 ACCESSBRIDGE_ARCH_ suffix + + $(call SetupNativeCompilation,BUILD_JAWTACCESSBRIDGE$1,\ + LIBRARY=JAWTAccessBridge$1,\ + OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ + SRC:=$(ACCESSBRIDGE_SRCDIR),\ + INCLUDE_FILES:=JAWTAccessBridge.cpp,\ + LANG:=C++,\ + OPTIMIZATION:=LOW,\ + CFLAGS:=$(CFLAGS_JDKLIB) \ + -DACCESSBRIDGE_ARCH_$3,\ + LDFLAGS:=$(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \ + winspool.lib jawt.lib comdlg32.lib advapi32.lib shell32.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \ + -subsystem:windows -machine:$2 \ + -def:$(ACCESSBRIDGE_SRCDIR)/JAWTAccessBridge.DEF,\ + VERSIONINFO_RESOURCE:=$(ACCESSBRIDGE_SRCDIR)/AccessBridgeStatusWindow.rc,\ + RC_FLAGS:=$(RC_FLAGS),\ + OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjawtaccessbridge$1,\ + DEBUG_SYMBOLS:=true) + + $$(BUILD_JAWTACCESSBRIDGE$1): $(JDK_OUTPUTDIR)/lib/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX) + + $(call SetupNativeCompilation,BUILD_JAVAACCESSBRIDGE$1,\ + LIBRARY=JavaAccessBridge$1,\ + OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ + SRC:=$(ACCESSBRIDGE_SRCDIR),\ + INCLUDE_FILES:=AccessBridgeATInstance.cpp AccessBridgeDebug.cpp \ + AccessBridgeJavaEntryPoints.cpp \ + AccessBridgeMessages.cpp JavaAccessBridge.cpp,\ + LANG:=C++,\ + OPTIMIZATION:=LOW,\ + CFLAGS:=$(CFLAGS_JDKLIB) \ + -DACCESSBRIDGE_ARCH_$3,\ + LDFLAGS:=$(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \ + winspool.lib comdlg32.lib advapi32.lib shell32.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \ + -subsystem:windows -machine:$2 \ + -def:$(ACCESSBRIDGE_SRCDIR)/JavaAccessBridge.DEF,\ + VERSIONINFO_RESOURCE:=$(ACCESSBRIDGE_SRCDIR)/AccessBridgeStatusWindow.rc,\ + RC_FLAGS:=$(RC_FLAGS),\ + OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjavaaccessbridge$1,\ + DEBUG_SYMBOLS:=true) + + $(call SetupNativeCompilation,BUILD_WINDOWSACCESSBRIDGE$1,\ + LIBRARY=WindowsAccessBridge$1,\ + OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ + SRC:=$(ACCESSBRIDGE_SRCDIR),\ + INCLUDE_FILES:=AccessBridgeJavaVMInstance.cpp AccessBridgeMessageQueue.cpp \ + AccessBridgeMessages.cpp AccessBridgeWindowsEntryPoints.cpp \ + WinAccessBridge.cpp AccessBridgeDebug.cpp \ + AccessBridgeEventHandler.cpp,\ + LANG:=C++,\ + OPTIMIZATION:=LOW,\ + CFLAGS:=$(filter-out -MD,$(CFLAGS_JDKLIB)) -MT \ + -DACCESSBRIDGE_ARCH_$3,\ + LDFLAGS:=$(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \ + winspool.lib comdlg32.lib advapi32.lib shell32.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \ + -subsystem:windows -machine:$2 \ + -def:$(ACCESSBRIDGE_SRCDIR)/WinAccessBridge.DEF,\ + VERSIONINFO_RESOURCE:=$(ACCESSBRIDGE_SRCDIR)/AccessBridgeStatusWindow.rc,\ + RC_FLAGS:=$(RC_FLAGS),\ + OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libwindowsaccessbridge$1,\ + DEBUG_SYMBOLS:=true) + + BUILD_LIBRARIES += $$(BUILD_JAWTACCESSBRIDGE$1) $$(BUILD_JAVAACCESSBRIDGE$1) \ + $$(BUILD_WINDOWSACCESSBRIDGE$1) + + endef + + ifeq ($(OPENJDK_TARGET_CPU_BITS),32) + $(eval $(call SetupAccessBridge,-32,I386,32)) + $(eval $(call SetupAccessBridge,,I386,LEGACY)) + else + $(eval $(call SetupAccessBridge,-64,X64,64)) + endif +endif +endif + + ########################################################################################## all: $(COPY_FILES) $(BUILD_LIBRARIES) diff --git a/jdk/makefiles/CopyFiles.gmk b/jdk/makefiles/CopyFiles.gmk index 8f99a113d3d..9c4dc0d7dec 100644 --- a/jdk/makefiles/CopyFiles.gmk +++ b/jdk/makefiles/CopyFiles.gmk @@ -42,7 +42,7 @@ H_TARGET_FILES =$(INCLUDEDIR)/jdwpTransport.h \ $(INCLUDEDIR)/jvmticmlr.h \ $(INCLUDEDIR)/classfile_constants.h \ $(INCLUDEDIR)/jawt.h \ - $(OPENJDK_TARGET_OS_INCLUDE)/jni_md.h \ + $(OPENJDK_TARGET_OS_INCLUDE)/jni_md.h \ $(OPENJDK_TARGET_OS_INCLUDE)/jawt_md.h $(INCLUDEDIR)/%.h: $(JDK_TOPDIR)/src/share/javavm/export/%.h @@ -59,6 +59,27 @@ COPY_FILES = $(H_TARGET_FILES) ########################################################################################## +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS), windows) + COPY_FILES += $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgeCallbacks.h \ + $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgeCalls.h \ + $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgePackages.h \ + $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgeCalls.c \ + $(JDK_OUTPUTDIR)/lib/accessibility.properties + + $(OPENJDK_TARGET_OS_INCLUDE)/bridge/%: \ + $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/% + $(install-file) + + $(JDK_OUTPUTDIR)/lib/accessibility.properties: \ + $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/accessibility.properties + $(install-file) + +endif +endif + +########################################################################################## + LIBDIR = $(JDK_OUTPUTDIR)/lib SERVICETAG_LIBDIR = $(LIBDIR)/servicetag @@ -267,10 +288,12 @@ endif ifeq ($(OPENJDK_TARGET_OS),windows) MSVCR_TARGET := $(JDK_OUTPUTDIR)/bin/$(notdir $(MSVCR_DLL)) + # Chmod to avoid permission issues if bundles are unpacked on unix platforms. $(MSVCR_TARGET): $(MSVCR_DLL) $(MKDIR) -p $(@D) $(RM) $@ $(CP) $< $@ + $(CHMOD) a+rx $@ COPY_FILES += $(MSVCR_TARGET) endif diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk index 6250dd83fe2..dc93edb7e6a 100644 --- a/jdk/makefiles/CreateJars.gmk +++ b/jdk/makefiles/CreateJars.gmk @@ -72,6 +72,13 @@ JARS+=$(IMAGES_OUTPUTDIR)/lib/ext/dnsns.jar ########################################################################################## +$(IMAGES_OUTPUTDIR)/lib/tzdb.jar: $(JDK_OUTPUTDIR)/lib/tzdb.jar + $(install-file) + +JARS += $(IMAGES_OUTPUTDIR)/lib/tzdb.jar + +########################################################################################## + LOCALEDATA_INCLUDE_LOCALES := ar be bg ca cs da de el es et fi fr ga hi hr hu in is it \ iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \ th tr uk vi zh @@ -134,6 +141,7 @@ RT_JAR_EXCLUDES := \ com/sun/crypto/provider \ com/sun/istack/internal/tools \ com/sun/jarsigner \ + com/sun/java/accessibility \ com/sun/javadoc \ com/sun/jdi \ com/sun/net/ssl/internal/ssl \ @@ -934,6 +942,47 @@ JARS+=$(IMAGES_OUTPUTDIR)/src.zip ########################################################################################## +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS), windows) + + $(eval $(call SetupArchive,BUILD_JACCESS_JAR,,\ + SRCS:=$(JDK_OUTPUTDIR)/classes,\ + INCLUDES:=com/sun/java/accessibility/util,\ + JAR:=$(IMAGES_OUTPUTDIR)/lib/ext/jaccess.jar,\ + SKIP_METAINF:=true)) + + JARS += $(IMAGES_OUTPUTDIR)/lib/ext/jaccess.jar + + ifeq ($(OPENJDK_TARGET_CPU_BITS), 32) + $(eval $(call SetupArchive,BUILD_ACCESSBRIDGE_32_JAR,,\ + SRCS:=$(JDK_OUTPUTDIR)/classes_ab/32bit $(JDK_OUTPUTDIR)/classes,\ + INCLUDES:=com/sun/java/accessibility,\ + JAR:=$(IMAGES_OUTPUTDIR)/lib/ext/access-bridge-32.jar,\ + SKIP_METAINF:=true)) + + $(eval $(call SetupArchive,BUILD_ACCESSBRIDGE_LEGACY_JAR,,\ + SRCS:=$(JDK_OUTPUTDIR)/classes_ab/legacy $(JDK_OUTPUTDIR)/classes,\ + INCLUDES:=com/sun/java/accessibility,\ + JAR:=$(IMAGES_OUTPUTDIR)/lib/ext/access-bridge.jar,\ + SKIP_METAINF:=true)) + + JARS += $(IMAGES_OUTPUTDIR)/lib/ext/access-bridge-32.jar \ + $(IMAGES_OUTPUTDIR)/lib/ext/access-bridge.jar + else + $(eval $(call SetupArchive,BUILD_ACCESSBRIDGE_64_JAR,,\ + SRCS:=$(JDK_OUTPUTDIR)/classes_ab/64bit $(JDK_OUTPUTDIR)/classes,\ + INCLUDES:=com/sun/java/accessibility,\ + EXCLUDES:=com/sun/java/accessibility/util/java,\ + JAR:=$(IMAGES_OUTPUTDIR)/lib/ext/access-bridge-64.jar,\ + SKIP_METAINF:=true)) + + JARS += $(IMAGES_OUTPUTDIR)/lib/ext/access-bridge-64.jar + endif +endif +endif + +########################################################################################## + # # This is an empty jar (only contains manifest) and fits poorly into framework... # create simple rule instead diff --git a/jdk/makefiles/GendataTZDB.gmk b/jdk/makefiles/GendataTZDB.gmk new file mode 100644 index 00000000000..3c608fb06ba --- /dev/null +++ b/jdk/makefiles/GendataTZDB.gmk @@ -0,0 +1,44 @@ +# +# 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. +# + +GENDATA_TZDB := + +# +# Time zone data file creation +# +TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata +TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) +TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE)) + +GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib +GENDATA_TZDB_JAR := tzdb.jar + +$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES) + $(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) + echo building tzdb from version $(TZDATA_VER) + $(TOOL_TZDB) -verbose -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE) + +GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) diff --git a/jdk/makefiles/GenerateData.gmk b/jdk/makefiles/GenerateData.gmk index f57741700b9..7d7e16b6903 100644 --- a/jdk/makefiles/GenerateData.gmk +++ b/jdk/makefiles/GenerateData.gmk @@ -47,6 +47,9 @@ GENDATA += $(GENDATA_FONT_CONFIG) include GendataTimeZone.gmk GENDATA += $(GENDATA_TIMEZONE) +include GendataTZDB.gmk +GENDATA += $(GENDATA_TZDB) + include GendataHtml32dtd.gmk GENDATA += $(GENDATA_HTML32DTD) diff --git a/jdk/makefiles/GensrcMisc.gmk b/jdk/makefiles/GensrcMisc.gmk index 7fdfa3c846c..5b9c06e5abf 100644 --- a/jdk/makefiles/GensrcMisc.gmk +++ b/jdk/makefiles/GensrcMisc.gmk @@ -190,3 +190,36 @@ $(JDK_OUTPUTDIR)/gensrc/sun/nio/fs/SolarisConstants.java : $(BUILD_GENSRC_SOL_EX endif + +########################################################################################## + +ifndef OPENJDK +ifeq ($(OPENJDK_TARGET_OS), windows) + + AB_GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc_ab + AB_SRC_DIR := $(JDK_TOPDIR)/src/closed/windows/classes/com/sun/java/accessibility + + ifeq ($(OPENJDK_TARGET_CPU_BITS), 32) + $(AB_GENSRC_DIR)/32bit/com/sun/java/accessibility/AccessBridge.java: \ + $(AB_SRC_DIR)/32bit/AccessBridge.java + $(install-file) + + $(AB_GENSRC_DIR)/legacy/com/sun/java/accessibility/AccessBridge.java: \ + $(AB_SRC_DIR)/legacy/AccessBridge.java + $(install-file) + + GENSRC_MISC += $(AB_GENSRC_DIR)/32bit/com/sun/java/accessibility/AccessBridge.java \ + $(AB_GENSRC_DIR)/legacy/com/sun/java/accessibility/AccessBridge.java + + else + $(AB_GENSRC_DIR)/64bit/com/sun/java/accessibility/AccessBridge.java: \ + $(AB_SRC_DIR)/64bit/AccessBridge.java + $(install-file) + + GENSRC_MISC += $(AB_GENSRC_DIR)/64bit/com/sun/java/accessibility/AccessBridge.java + + endif +endif +endif + +########################################################################################## \ No newline at end of file diff --git a/jdk/makefiles/Tools.gmk b/jdk/makefiles/Tools.gmk index a794d745520..811dd47fe28 100644 --- a/jdk/makefiles/Tools.gmk +++ b/jdk/makefiles/Tools.gmk @@ -106,6 +106,10 @@ TOOL_JARSPLIT=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.javazic.Main +TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ + build.tools.tzdb.TzdbZoneRulesCompiler + + # TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml # and nbproject/project.properties in the same dir. Needs to be looked at. TOOL_JDWPGEN=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses build.tools.jdwpgen.Main diff --git a/jdk/makefiles/mapfiles/libjava/mapfile-vers b/jdk/makefiles/mapfiles/libjava/mapfile-vers index 97938361c99..81e678d7624 100644 --- a/jdk/makefiles/mapfiles/libjava/mapfile-vers +++ b/jdk/makefiles/mapfiles/libjava/mapfile-vers @@ -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 @@ -189,6 +189,7 @@ SUNWprivate_1.1 { Java_java_lang_reflect_Array_setInt; Java_java_lang_reflect_Array_setLong; Java_java_lang_reflect_Array_setShort; + Java_java_lang_reflect_Executable_getParameters0; Java_java_lang_Runtime_freeMemory; Java_java_lang_Runtime_maxMemory; Java_java_lang_Runtime_gc; diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaKeyBindings.java b/jdk/src/macosx/classes/com/apple/laf/AquaKeyBindings.java index bbb804ae3f1..88db59f0b9f 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaKeyBindings.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaKeyBindings.java @@ -142,6 +142,21 @@ public class AquaKeyBindings { })); } + LateBoundInputMap getPasswordFieldInputMap() { + return new LateBoundInputMap(new SimpleBinding(getTextFieldInputMap().getBindings()), + // nullify all the bindings that may discover space characters in the text + new SimpleBinding(new String[] { + "alt LEFT", null, + "alt KP_LEFT", null, + "alt RIGHT", null, + "alt KP_RIGHT", null, + "shift alt LEFT", null, + "shift alt KP_LEFT", null, + "shift alt RIGHT", null, + "shift alt KP_RIGHT", null, + })); + } + LateBoundInputMap getMultiLineTextInputMap() { return new LateBoundInputMap(new SimpleBinding(commonTextEditorBindings), new SimpleBinding(new String[] { "ENTER", DefaultEditorKit.insertBreakAction, diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/jdk/src/macosx/classes/com/apple/laf/AquaLookAndFeel.java index 4f108da2df0..457b82d36a3 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -697,7 +697,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel { "Panel.foreground", black, "Panel.opaque", useOpaqueComponents, - "PasswordField.focusInputMap", aquaKeyBindings.getTextFieldInputMap(), + "PasswordField.focusInputMap", aquaKeyBindings.getPasswordFieldInputMap(), "PasswordField.font", controlFont, "PasswordField.background", textBackground, "PasswordField.foreground", textForeground, diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaPainter.java b/jdk/src/macosx/classes/com/apple/laf/AquaPainter.java index cfafa43d9de..303938d5988 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaPainter.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -37,7 +37,6 @@ import sun.awt.image.*; import sun.java2d.*; import sun.print.*; import apple.laf.*; -import apple.laf.JRSUIConstants.Widget; import apple.laf.JRSUIUtils.NineSliceMetricsProvider; abstract class AquaPainter { @@ -63,7 +62,7 @@ abstract class AquaPainter { } static AquaPainter create(final T state, final NineSliceMetricsProvider metricsProvider) { - return new AquaNineSlicingImagePainter(state, metricsProvider); + return new AquaNineSlicingImagePainter<>(state, metricsProvider); } abstract void paint(final Graphics2D g, final T stateToPaint, final Component c); @@ -71,7 +70,7 @@ abstract class AquaPainter { final Rectangle boundsRect = new Rectangle(); final JRSUIControl control; T state; - public AquaPainter(final JRSUIControl control, final T state) { + AquaPainter(final JRSUIControl control, final T state) { this.control = control; this.state = state; } @@ -94,14 +93,14 @@ abstract class AquaPainter { protected final HashMap slicedControlImages; protected final NineSliceMetricsProvider metricsProvider; - public AquaNineSlicingImagePainter(final T state) { + AquaNineSlicingImagePainter(final T state) { this(state, null); } - public AquaNineSlicingImagePainter(final T state, final NineSliceMetricsProvider metricsProvider) { + AquaNineSlicingImagePainter(final T state, final NineSliceMetricsProvider metricsProvider) { super(new JRSUIControl(false), state); this.metricsProvider = metricsProvider; - slicedControlImages = new HashMap(); + slicedControlImages = new HashMap<>(); } @Override @@ -127,7 +126,7 @@ abstract class AquaPainter { } static class AquaSingleImagePainter extends AquaPainter { - public AquaSingleImagePainter(final T state) { + AquaSingleImagePainter(final T state) { super(new JRSUIControl(false), state); } @@ -137,12 +136,12 @@ abstract class AquaPainter { } static void paintFromSingleCachedImage(final Graphics2D g, final JRSUIControl control, final JRSUIState controlState, final Component c, final Rectangle boundsRect) { - Rectangle clipRect = g.getClipBounds(); - Rectangle intersection = boundsRect.intersection(clipRect); + final Rectangle clipRect = g.getClipBounds(); + final Rectangle intersection = boundsRect.intersection(clipRect); if (intersection.width <= 0 || intersection.height <= 0) return; - int imgX1 = intersection.x - boundsRect.x; - int imgY1 = intersection.y - boundsRect.y; + final int imgX1 = intersection.x - boundsRect.x; + final int imgY1 = intersection.y - boundsRect.y; final GraphicsConfiguration config = g.getDeviceConfiguration(); final ImageCache cache = ImageCache.getInstance(); @@ -150,20 +149,15 @@ abstract class AquaPainter { if (image == null) { image = new BufferedImage(boundsRect.width, boundsRect.height, BufferedImage.TYPE_INT_ARGB_PRE); cache.setImage(image, config, boundsRect.width, boundsRect.height, controlState); - } else { - g.drawImage(image, intersection.x, intersection.y, intersection.x + intersection.width, intersection.y + intersection.height, - imgX1, imgY1, imgX1 + intersection.width, imgY1 + intersection.height, null); - return; + final WritableRaster raster = image.getRaster(); + final DataBufferInt buffer = (DataBufferInt)raster.getDataBuffer(); + + control.set(controlState); + control.paint(SunWritableRaster.stealData(buffer, 0), + image.getWidth(), image.getHeight(), 0, 0, boundsRect.width, boundsRect.height); + SunWritableRaster.markDirty(buffer); } - final WritableRaster raster = image.getRaster(); - final DataBufferInt buffer = (DataBufferInt)raster.getDataBuffer(); - - control.set(controlState); - control.paint(SunWritableRaster.stealData(buffer, 0), - image.getWidth(), image.getHeight(), 0, 0, boundsRect.width, boundsRect.height); - SunWritableRaster.markDirty(buffer); - g.drawImage(image, intersection.x, intersection.y, intersection.x + intersection.width, intersection.y + intersection.height, imgX1, imgY1, imgX1 + intersection.width, imgY1 + intersection.height, null); } @@ -173,7 +167,7 @@ abstract class AquaPainter { final JRSUIControl control; final JRSUIState state; - public RecyclableJRSUISlicedImageControl(final JRSUIControl control, final JRSUIState state, final NineSliceMetrics metrics) { + RecyclableJRSUISlicedImageControl(final JRSUIControl control, final JRSUIState state, final NineSliceMetrics metrics) { super(metrics); this.control = control; this.state = state; diff --git a/jdk/src/macosx/classes/com/apple/laf/ImageCache.java b/jdk/src/macosx/classes/com/apple/laf/ImageCache.java index 7ed83ae961c..f9af5c06161 100644 --- a/jdk/src/macosx/classes/com/apple/laf/ImageCache.java +++ b/jdk/src/macosx/classes/com/apple/laf/ImageCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -30,6 +30,7 @@ import java.lang.ref.*; import java.util.*; import java.util.concurrent.locks.*; +import apple.laf.JRSUIConstants; import apple.laf.JRSUIState; import com.apple.laf.AquaUtils.RecyclableSingleton; @@ -38,9 +39,9 @@ import com.apple.laf.AquaUtils.RecyclableSingleton; * SoftReferences so they will be dropped by the GC if heap memory gets tight. When our size hits max pixel count least * recently requested images are removed first. */ -class ImageCache { +final class ImageCache { // Ordered Map keyed by args hash, ordered by most recent accessed entry. - private final LinkedHashMap map = new LinkedHashMap(16, 0.75f, true); + private final LinkedHashMap map = new LinkedHashMap<>(16, 0.75f, true); // Maximum number of pixels to cache, this is used if maxCount private final int maxPixelCount; @@ -50,7 +51,7 @@ class ImageCache { // Lock for concurrent access to map private final ReadWriteLock lock = new ReentrantReadWriteLock(); // Reference queue for tracking lost softreferences to images in the cache - private final ReferenceQueue referenceQueue = new ReferenceQueue(); + private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); // Singleton Instance private static final RecyclableSingleton instance = new RecyclableSingleton() { @@ -63,11 +64,11 @@ class ImageCache { return instance.get(); } - public ImageCache(final int maxPixelCount) { + ImageCache(final int maxPixelCount) { this.maxPixelCount = maxPixelCount; } - public ImageCache() { + ImageCache() { this((8 * 1024 * 1024) / 4); // 8Mb of pixels } @@ -99,10 +100,13 @@ class ImageCache { * @param config The graphics configuration, needed if cached image is a Volatile Image. Used as part of cache key * @param w The image width, used as part of cache key * @param h The image height, used as part of cache key - * @param args Other arguments to use as part of the cache key - * @return true if the image could be cached or false if the image is too big + * @return true if the image could be cached, false otherwise. */ public boolean setImage(final Image image, final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { + if (state.is(JRSUIConstants.Animating.YES)) { + return false; + } + final int hash = hash(config, w, h, state); lock.writeLock().lock(); @@ -167,7 +171,7 @@ class ImageCache { private final int h; private final JRSUIState state; - public PixelCountSoftReference(final Image referent, final ReferenceQueue q, final int pixelCount, final int hash, final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { + PixelCountSoftReference(final Image referent, final ReferenceQueue q, final int pixelCount, final int hash, final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { super(referent, q); this.pixelCount = pixelCount; this.hash = hash; diff --git a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java index 2b884538839..bcb24ea46f7 100644 --- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java +++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java @@ -30,6 +30,7 @@ import java.awt.GraphicsDevice; import java.awt.Window; import java.awt.AWTPermission; import java.awt.DisplayMode; +import java.util.Objects; import sun.java2d.opengl.CGLGraphicsConfig; @@ -122,12 +123,12 @@ public final class CGraphicsDevice extends GraphicsDevice { boolean fsSupported = isFullScreenSupported(); if (fsSupported && old != null) { - // enter windowed mode (and restore original display mode) - exitFullScreenExclusive(old); + // restore original display mode and enter windowed mode. if (originalMode != null) { setDisplayMode(originalMode); originalMode = null; } + exitFullScreenExclusive(old); } super.setFullScreenWindow(w); @@ -186,13 +187,20 @@ public final class CGraphicsDevice extends GraphicsDevice { } @Override - public void setDisplayMode(DisplayMode dm) { + public void setDisplayMode(final DisplayMode dm) { if (dm == null) { throw new IllegalArgumentException("Invalid display mode"); } - nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), dm.getBitDepth(), dm.getRefreshRate()); - if (isFullScreenSupported() && getFullScreenWindow() != null) { - getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight()); + if (!Objects.equals(dm, getDisplayMode())) { + final Window w = getFullScreenWindow(); + if (w != null) { + exitFullScreenExclusive(w); + } + nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), + dm.getBitDepth(), dm.getRefreshRate()); + if (isFullScreenSupported() && w != null) { + enterFullScreenExclusive(w); + } } } diff --git a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java index 55b4665a752..aa9b798c617 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java @@ -1226,7 +1226,7 @@ public abstract class LWComponentPeer sendEventToDelegate(e); } - private void sendEventToDelegate(final AWTEvent e) { + protected void sendEventToDelegate(final AWTEvent e) { synchronized (getDelegateLock()) { if (getDelegate() == null || !isShowing() || !isEnabled()) { return; diff --git a/jdk/src/macosx/classes/sun/lwawt/LWScrollPanePeer.java b/jdk/src/macosx/classes/sun/lwawt/LWScrollPanePeer.java index 1e386f25725..723a9dd8da7 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWScrollPanePeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWScrollPanePeer.java @@ -29,6 +29,7 @@ import javax.swing.*; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; import java.awt.*; +import java.awt.event.MouseWheelEvent; import java.awt.peer.ScrollPanePeer; import java.util.List; @@ -51,6 +52,21 @@ final class LWScrollPanePeer extends LWContainerPeer return sp; } + @Override + public void handleEvent(AWTEvent e) { + if (e instanceof MouseWheelEvent) { + MouseWheelEvent wheelEvent = (MouseWheelEvent) e; + //java.awt.ScrollPane consumes the event + // in case isWheelScrollingEnabled() is true, + // forcibly send the consumed event to the delegate + if (getTarget().isWheelScrollingEnabled() && wheelEvent.isConsumed()) { + sendEventToDelegate(wheelEvent); + } + } else { + super.handleEvent(e); + } + } + @Override public void stateChanged(final ChangeEvent e) { SwingUtilities.invokeLater(new Runnable() { diff --git a/jdk/src/macosx/classes/sun/lwawt/LWTextFieldPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWTextFieldPeer.java index 7532f620149..ef2b4d087e2 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWTextFieldPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWTextFieldPeer.java @@ -34,7 +34,7 @@ import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.peer.TextFieldPeer; -import javax.swing.JPasswordField; +import javax.swing.*; import javax.swing.text.JTextComponent; final class LWTextFieldPeer @@ -48,7 +48,7 @@ final class LWTextFieldPeer @Override protected JPasswordField createDelegate() { - return new JTextAreaDelegate(); + return new JPasswordFieldDelegate(); } @Override @@ -69,9 +69,18 @@ final class LWTextFieldPeer public void setEchoChar(final char echoChar) { synchronized (getDelegateLock()) { getDelegate().setEchoChar(echoChar); - getDelegate().putClientProperty("JPasswordField.cutCopyAllowed", - getDelegate().echoCharIsSet() - ? Boolean.FALSE : Boolean.TRUE); + final boolean cutCopyAllowed; + final String focusInputMapKey; + if (echoChar != 0) { + cutCopyAllowed = false; + focusInputMapKey = "PasswordField.focusInputMap"; + } else { + cutCopyAllowed = true; + focusInputMapKey = "TextField.focusInputMap"; + } + getDelegate().putClientProperty("JPasswordField.cutCopyAllowed", cutCopyAllowed); + InputMap inputMap = (InputMap) UIManager.get(focusInputMapKey); + SwingUtilities.replaceUIInputMap(getDelegate(), JComponent.WHEN_FOCUSED, inputMap); } } @@ -106,11 +115,11 @@ final class LWTextFieldPeer super.handleJavaFocusEvent(e); } - private final class JTextAreaDelegate extends JPasswordField { + private final class JPasswordFieldDelegate extends JPasswordField { // Empty non private constructor was added because access to this // class shouldn't be emulated by a synthetic accessor method. - JTextAreaDelegate() { + JPasswordFieldDelegate() { super(); } diff --git a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java index 57a8642b6d0..89f39fccbf8 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.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 @@ -539,7 +539,7 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { @Override public void ungrab(Window w) { if (w.getPeer() != null) { - ((LWWindowPeer)w.getPeer()).ungrab(); + ((LWWindowPeer)w.getPeer()).ungrab(false); } } } diff --git a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java index 9d583e65749..5b19788f244 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -53,7 +53,7 @@ public class LWWindowPeer private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer"); - private PlatformWindow platformWindow; + private final PlatformWindow platformWindow; // Window bounds reported by the native system (as opposed to // regular bounds inherited from LWComponentPeer which are @@ -554,12 +554,14 @@ public class LWWindowPeer /** * Called by the {@code PlatformWindow} when this window is moved/resized by - * user. There's no notifyReshape() in LWComponentPeer as the only - * components which could be resized by user are top-level windows. + * user or window insets are changed. There's no notifyReshape() in + * LWComponentPeer as the only components which could be resized by user are + * top-level windows. */ public final void notifyReshape(int x, int y, int w, int h) { final boolean moved; final boolean resized; + final boolean invalid = updateInsets(platformWindow.getInsets()); synchronized (getStateLock()) { moved = (x != sysX) || (y != sysY); resized = (w != sysW) || (h != sysH); @@ -570,7 +572,7 @@ public class LWWindowPeer } // Check if anything changed - if (!moved && !resized) { + if (!moved && !resized && !invalid) { return; } // First, update peer's bounds @@ -584,10 +586,10 @@ public class LWWindowPeer } // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events - if (moved) { + if (moved || invalid) { handleMove(x, y, true); } - if (resized) { + if (resized || invalid) { handleResize(w, h, true); repaintPeer(); } @@ -999,27 +1001,21 @@ public class LWWindowPeer } } - /* - * Request the window insets from the delegate and compares it - * with the current one. This method is mostly called by the - * delegate, e.g. when the window state is changed and insets - * should be recalculated. - * + /** + * Request the window insets from the delegate and compares it with the + * current one. This method is mostly called by the delegate, e.g. when the + * window state is changed and insets should be recalculated. + *

* This method may be called on the toolkit thread. */ - public boolean updateInsets(Insets newInsets) { - boolean changed = false; + public final boolean updateInsets(final Insets newInsets) { synchronized (getStateLock()) { - changed = (insets.equals(newInsets)); + if (insets.equals(newInsets)) { + return false; + } insets = newInsets; } - - if (changed) { - replaceSurfaceData(); - repaintPeer(); - } - - return changed; + return true; } public static LWWindowPeer getWindowUnderCursor() { @@ -1208,13 +1204,19 @@ public class LWWindowPeer grabbingWindow = this; } - void ungrab() { + final void ungrab(boolean doPost) { if (isGrabbing()) { grabbingWindow = null; - postEvent(new UngrabEvent(getTarget())); + if (doPost) { + postEvent(new UngrabEvent(getTarget())); + } } } + void ungrab() { + ungrab(true); + } + private boolean isGrabbing() { return this == grabbingWindow; } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java index 459895523e2..5b56b19ac1c 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java @@ -273,8 +273,31 @@ public class CDataTransferer extends DataTransferer { @Override protected ByteArrayOutputStream convertFileListToBytes(ArrayList fileList) throws IOException { - // TODO Auto-generated method stub - return null; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + for (int i = 0; i < fileList.size(); i++) + { + byte[] bytes = fileList.get(i).getBytes(); + bos.write(bytes, 0, bytes.length); + bos.write(0); + } + return bos; + } + + @Override + protected boolean isURIListFormat(long format) { + String nat = getNativeForFormat(format); + if (nat == null) { + return false; + } + try { + DataFlavor df = new DataFlavor(nat); + if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) { + return true; + } + } catch (Exception e) { + // Not a MIME format. + } + return false; } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java index 4972301e780..495657963bd 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java @@ -27,7 +27,6 @@ package sun.lwawt.macosx; import java.awt.*; import java.awt.geom.Rectangle2D; -import java.awt.image.VolatileImage; import sun.awt.CGraphicsConfig; import sun.awt.CGraphicsEnvironment; @@ -89,29 +88,8 @@ public class CPlatformView extends CFRetainedResource { return peer; } - public void enterFullScreenMode(final long nsWindowPtr) { + public void enterFullScreenMode() { CWrapper.NSView.enterFullScreenMode(ptr); - - // REMIND: CGLSurfaceData expects top-level's size - // and therefore we need to account insets before - // recreating the surface data - Insets insets = peer.getInsets(); - - Rectangle screenBounds; - final long screenPtr = CWrapper.NSWindow.screen(nsWindowPtr); - try { - screenBounds = CWrapper.NSScreen.frame(screenPtr).getBounds(); - } finally { - CWrapper.NSObject.release(screenPtr); - } - - // the move/size notification from the underlying system comes - // but it contains a bounds smaller than the whole screen - // and therefore we need to create the synthetic notifications - peer.notifyReshape(screenBounds.x - insets.left, - screenBounds.y - insets.bottom, - screenBounds.width + insets.left + insets.right, - screenBounds.height + insets.top + insets.bottom); } public void exitFullScreenMode() { diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index b489eae96b6..8f83702a209 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -38,7 +38,6 @@ import sun.awt.*; import sun.java2d.SurfaceData; import sun.java2d.opengl.CGLSurfaceData; import sun.lwawt.*; -import sun.lwawt.LWWindowPeer.PeerType; import sun.util.logging.PlatformLogger; import com.apple.laf.*; @@ -58,7 +57,6 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor private static native void nativeRevalidateNSWindowShadow(long nsWindowPtr); private static native void nativeSetNSWindowMinimizedIcon(long nsWindowPtr, long nsImage); private static native void nativeSetNSWindowRepresentedFilename(long nsWindowPtr, String representedFilename); - private static native void nativeSetNSWindowSecurityWarningPositioning(long nsWindowPtr, double x, double y, float biasX, float biasY); private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled); private static native void nativeSynthesizeMouseEnteredExitedEvents(); private static native void nativeDispose(long nsWindowPtr); @@ -197,7 +195,8 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor // 1) setting native bounds via nativeSetBounds() call // 2) getting notification from the native level via deliverMoveResizeEvent() private Rectangle nativeBounds = new Rectangle(0, 0, 0, 0); - private volatile boolean isFullScreenMode = false; + private volatile boolean isFullScreenMode; + private boolean isFullScreenAnimationOn; private Window target; private LWWindowPeer peer; @@ -415,8 +414,10 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor @Override // PlatformWindow public Insets getInsets() { - final Insets insets = nativeGetNSWindowInsets(getNSWindowPtr()); - return insets; + if (!isFullScreenMode) { + return nativeGetNSWindowInsets(getNSWindowPtr()); + } + return new Insets(0, 0, 0, 0); } @Override // PlatformWindow @@ -728,7 +729,19 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor @Override public void enterFullScreenMode() { isFullScreenMode = true; - contentView.enterFullScreenMode(getNSWindowPtr()); + contentView.enterFullScreenMode(); + // the move/size notification from the underlying system comes + // but it contains a bounds smaller than the whole screen + // and therefore we need to create the synthetic notifications + Rectangle screenBounds; + final long screenPtr = CWrapper.NSWindow.screen(getNSWindowPtr()); + try { + screenBounds = CWrapper.NSScreen.frame(screenPtr).getBounds(); + } finally { + CWrapper.NSObject.release(screenPtr); + } + peer.notifyReshape(screenBounds.x, screenBounds.y, screenBounds.width, + screenBounds.height); } @Override @@ -875,11 +888,10 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor final Rectangle oldB = nativeBounds; nativeBounds = new Rectangle(x, y, width, height); peer.notifyReshape(x, y, width, height); - if (byUser && !oldB.getSize().equals(nativeBounds.getSize())) { + if ((byUser && !oldB.getSize().equals(nativeBounds.getSize())) + || isFullScreenAnimationOn) { flushBuffers(); } - //TODO validateSurface already called from notifyReshape - validateSurface(); } private void deliverWindowClosingEvent() { @@ -924,6 +936,10 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor return false; } + if (blocker instanceof CPrinterDialogPeer) { + return true; + } + CPlatformWindow pWindow = (CPlatformWindow)blocker.getPlatformWindow(); pWindow.orderAboveSiblings(); @@ -975,27 +991,19 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor orderAboveSiblings(); } - private void updateDisplay() { - EventQueue.invokeLater(new Runnable() { - public void run() { - validateSurface(); - } - }); - } - - private void updateWindowContent() { - ComponentEvent resizeEvent = new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED); - SunToolkit.postEvent(SunToolkit.targetToAppContext(target), resizeEvent); - } - private void windowWillEnterFullScreen() { - updateWindowContent(); + isFullScreenAnimationOn = true; } + private void windowDidEnterFullScreen() { - updateDisplay(); + isFullScreenAnimationOn = false; } + private void windowWillExitFullScreen() { - updateWindowContent(); + isFullScreenAnimationOn = true; + } + + private void windowDidExitFullScreen() { + isFullScreenAnimationOn = false; } - private void windowDidExitFullScreen() {} } diff --git a/jdk/src/macosx/native/sun/awt/AWTSurfaceLayers.m b/jdk/src/macosx/native/sun/awt/AWTSurfaceLayers.m index c6fec1fc392..6e9fbbca5ab 100644 --- a/jdk/src/macosx/native/sun/awt/AWTSurfaceLayers.m +++ b/jdk/src/macosx/native/sun/awt/AWTSurfaceLayers.m @@ -101,8 +101,7 @@ Java_sun_lwawt_macosx_CPlatformComponent_nativeCreateComponent JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + CALayer *windowLayer = jlong_to_ptr(windowLayerPtr); surfaceLayers = [[AWTSurfaceLayers alloc] initWithWindowLayer: windowLayer]; CFRetain(surfaceLayers); @@ -127,7 +126,6 @@ JNF_COCOA_ENTER(env); AWTSurfaceLayers *surfaceLayers = OBJC(surfaceLayersPtr); [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ - AWT_ASSERT_APPKIT_THREAD; CGRect rect = CGRectMake(x, y, width, height); [surfaceLayers setBounds: rect]; diff --git a/jdk/src/macosx/native/sun/awt/AWTView.m b/jdk/src/macosx/native/sun/awt/AWTView.m index 3770287a32a..cc16a2026ee 100644 --- a/jdk/src/macosx/native/sun/awt/AWTView.m +++ b/jdk/src/macosx/native/sun/awt/AWTView.m @@ -1243,8 +1243,7 @@ JNF_COCOA_ENTER(env); jobject cPlatformView = (*env)->NewGlobalRef(env, obj); [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + CALayer *windowLayer = jlong_to_ptr(windowLayerPtr); AWTView *view = [[AWTView alloc] initWithRect:rect platformView:cPlatformView @@ -1274,8 +1273,7 @@ JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + if (toResize) { [view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; } else { @@ -1308,8 +1306,7 @@ JNF_COCOA_ENTER(env); NSWindow *window = [view window]; [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + ret = (jint)[[AWTWindow getNSWindowDisplayID_AppKitThread: window] intValue]; }]; @@ -1336,8 +1333,7 @@ JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + NSRect viewBounds = [view bounds]; NSRect frameInWindow = [view convertRect:viewBounds toView:nil]; rect = [[view window] convertRectToScreen:frameInWindow]; @@ -1366,9 +1362,7 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPlatformView_nativeIsViewUnder JNF_COCOA_ENTER(env); NSView *nsView = OBJC(viewPtr); - [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ NSPoint ptWindowCoords = [[nsView window] mouseLocationOutsideOfEventStream]; NSPoint ptViewCoords = [nsView convertPoint:ptWindowCoords fromView:nil]; underMouse = [nsView hitTest:ptViewCoords] != nil; diff --git a/jdk/src/macosx/native/sun/awt/AWTWindow.m b/jdk/src/macosx/native/sun/awt/AWTWindow.m index fa27a3bf761..3af7c6c736f 100644 --- a/jdk/src/macosx/native/sun/awt/AWTWindow.m +++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m @@ -738,14 +738,12 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWind __block AWTWindow *window = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; JNFWeakJObjectWrapper *platformWindow = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env]; NSView *contentView = OBJC(contentViewPtr); NSRect frameRect = NSMakeRect(x, y, w, h); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow styleBits:styleBits @@ -770,11 +768,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowSt (JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; @@ -807,12 +803,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMe (JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); CMenuBar *menuBar = OBJC(menuBarPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; @@ -838,14 +832,12 @@ JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindo jobject ret = NULL; JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); __block NSRect contentRect = NSZeroRect; __block NSRect frame = NSZeroRect; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ frame = [nsWindow frame]; contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[nsWindow styleMask]]; @@ -873,14 +865,12 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBo (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSRect jrect = NSMakeRect(originX, originY, width, height); // TODO: not sure we need displayIfNeeded message in our view NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; @@ -913,7 +903,6 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMi (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; if (minW < 1) minW = 1; if (minH < 1) minH = 1; @@ -921,8 +910,7 @@ AWT_ASSERT_NOT_APPKIT_THREAD; if (maxH < 1) maxH = 1; NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; @@ -949,12 +937,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowT (JNIEnv *env, jclass clazz, jlong windowPtr) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [nsWindow orderBack:nil]; }]; @@ -970,11 +955,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowT (JNIEnv *env, jclass clazz, jlong windowPtr) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ if (![nsWindow isKeyWindow]) { [nsWindow makeKeyAndOrderFront:nsWindow]; @@ -995,7 +978,6 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTi (JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); [nsWindow performSelectorOnMainThread:@selector(setTitle:) @@ -1016,15 +998,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSW JNF_COCOA_ENTER(env); NSWindow *nsWindow = OBJC(windowPtr); - if ([NSThread isMainThread]) { + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [nsWindow invalidateShadow]; - } else { - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - - [nsWindow invalidateShadow]; - }]; - } + }]; JNF_COCOA_EXIT(env); } @@ -1060,13 +1036,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMi (JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); NSImage *image = OBJC(nsImagePtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [nsWindow setMiniwindowImage:image]; }]; @@ -1082,35 +1055,16 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRe (JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:JNFNormalizedNSStringForPath(env, filename)]; - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [nsWindow setRepresentedURL:url]; }]; JNF_COCOA_EXIT(env); } -/* - * Class: sun_lwawt_macosx_CPlatformWindow - * Method: nativeSetNSWindowSecurityWarningPositioning - * Signature: (JDDFF)V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowSecurityWarningPositioning -(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble x, jdouble y, jfloat biasX, jfloat biasY) -{ -JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; - - [JNFException raise:env as:kRuntimeException reason:"unimplemented"]; - -JNF_COCOA_EXIT(env); -} - /* * Class: sun_lwawt_macosx_CPlatformWindow * Method: nativeGetTopmostPlatformWindowUnderMouse @@ -1144,10 +1098,8 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMou (JNIEnv *env, jclass clazz) { JNF_COCOA_ENTER(env); - AWT_ASSERT_NOT_APPKIT_THREAD; - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows]; }]; @@ -1168,7 +1120,7 @@ JNF_COCOA_ENTER(env); SEL toggleFullScreenSelector = @selector(toggleFullScreen:); if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return; - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [nsWindow performSelector:toggleFullScreenSelector withObject:nil]; }]; @@ -1181,7 +1133,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetEnabled JNF_COCOA_ENTER(env); NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; [window setEnabled: isEnabled]; @@ -1196,7 +1148,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose JNF_COCOA_ENTER(env); NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; if ([AWTWindow lastKeyWindow] == window) { diff --git a/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m b/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m index 7ba5fcfe804..9a5aee94d44 100644 --- a/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m +++ b/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m @@ -515,10 +515,9 @@ AWT_ASSERT_APPKIT_THREAD; JNIEXPORT void JNICALL Java_com_apple_eawt_Application_nativeInitializeApplicationDelegate (JNIEnv *env, jclass clz) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); // Force initialization to happen on AppKit thread! - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [ApplicationDelegate sharedDelegate]; }]; JNF_COCOA_EXIT(env); @@ -532,10 +531,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeOpenCocoaAboutWindow (JNIEnv *env, jclass clz) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [NSApp orderFrontStandardAboutPanel:nil]; }]; @@ -550,10 +548,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeReplyToAppShouldTerminate (JNIEnv *env, jclass clz, jboolean doTerminate) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [NSApp replyToApplicationShouldTerminate:doTerminate]; }]; @@ -568,7 +565,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNotification (JNIEnv *env, jclass clz, jint notificationType) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(_registerForNotification:) onObject:[ApplicationDelegate class] @@ -586,13 +582,10 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockMenu (JNIEnv *env, jclass clz, jlong nsMenuPtr) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); NSMenu *menu = (NSMenu *)jlong_to_ptr(nsMenuPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [ApplicationDelegate sharedDelegate].fDockMenu = menu; }]; @@ -607,14 +600,13 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockIconImage (JNIEnv *env, jclass clz, jlong nsImagePtr) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); NSImage *_image = (NSImage *)jlong_to_ptr(nsImagePtr); - [JNFRunLoop performOnMainThread:@selector(_setDockIconImage:) - on:[ApplicationDelegate class] - withObject:_image - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(_setDockIconImage:) + on:[ApplicationDelegate class] + withObject:_image + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -629,12 +621,9 @@ JNIEXPORT jlong JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeGetDockIc { __block NSImage *image = nil; -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ image = [ApplicationDelegate _dockIconImage]; CFRetain(image); }]; @@ -652,13 +641,10 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockIconBadge (JNIEnv *env, jclass clz, jstring badge) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); NSString *badgeString = JNFJavaToNSString(env, badge); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ NSDockTile *dockTile = [NSApp dockTile]; [dockTile setBadgeLabel:badgeString]; [dockTile display]; @@ -675,12 +661,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeRequestActivation (JNIEnv *env, jclass clz, jboolean allWindows) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ NSApplicationActivationOptions options = allWindows ? NSApplicationActivateAllWindows : 0; options |= NSApplicationActivateIgnoringOtherApps; // without this, nothing happens! [[NSRunningApplication currentApplication] activateWithOptions:options]; @@ -697,12 +680,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeRequestUserAttention (JNIEnv *env, jclass clz, jboolean critical) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [NSApp requestUserAttention:critical ? NSCriticalRequest : NSInformationalRequest]; }]; @@ -717,13 +697,12 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeOpenHelpViewer (JNIEnv *env, jclass clz) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThread:@selector(showHelp:) - on:NSApp - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(showHelp:) + on:NSApp + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -736,7 +715,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeEnableSuddenTermination (JNIEnv *env, jclass clz) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [[NSProcessInfo processInfo] enableSuddenTermination]; // Foundation thread-safe @@ -752,7 +730,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeDisableSuddenTermination (JNIEnv *env, jclass clz) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [[NSProcessInfo processInfo] disableSuddenTermination]; // Foundation thread-safe @@ -768,12 +745,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMenuBarHandler_nativeSetMenuState (JNIEnv *env, jclass clz, jint menuID, jboolean visible, jboolean enabled) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ ApplicationDelegate *delegate = [ApplicationDelegate sharedDelegate]; switch (menuID) { case com_apple_eawt__AppMenuBarHandler_MENU_ABOUT: @@ -796,12 +770,10 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMenuBarHandler_nativeSetDefaultMenuBar (JNIEnv *env, jclass clz, jlong cMenuBarPtr) { -AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); CMenuBar *menu = (CMenuBar *)jlong_to_ptr(cMenuBarPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [ApplicationDelegate sharedDelegate].fDefaultMenuBar = menu; }]; diff --git a/jdk/src/macosx/native/sun/awt/CClipboard.m b/jdk/src/macosx/native/sun/awt/CClipboard.m index 36675974705..fb300f72971 100644 --- a/jdk/src/macosx/native/sun/awt/CClipboard.m +++ b/jdk/src/macosx/native/sun/awt/CClipboard.m @@ -109,7 +109,6 @@ static CClipboard *sClipboard = nil; } - (void) javaDeclareTypes:(NSArray *)inTypes withOwner:(jobject)inClipboard jniEnv:(JNIEnv *)inEnv { - AWT_ASSERT_NOT_APPKIT_THREAD; //NSLog(@"CClipboard javaDeclareTypes %@ withOwner", inTypes); @@ -134,7 +133,6 @@ static CClipboard *sClipboard = nil; - (NSArray *) javaGetTypes { - AWT_ASSERT_NOT_APPKIT_THREAD; NSMutableArray *args = [NSMutableArray arrayWithCapacity:1]; [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; @@ -152,7 +150,6 @@ static CClipboard *sClipboard = nil; } - (void) javaSetData:(NSData *)inData forType:(NSString *) inFormat { - AWT_ASSERT_NOT_APPKIT_THREAD; CClipboardUpdate *newUpdate = [[CClipboardUpdate alloc] initWithData:inData withFormat:inFormat]; [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) onObject:self withObject:newUpdate waitUntilDone:YES awtMode:YES]; @@ -171,7 +168,6 @@ static CClipboard *sClipboard = nil; } - (NSData *) javaGetDataForType:(NSString *) inFormat { - AWT_ASSERT_NOT_APPKIT_THREAD; NSMutableArray *args = [NSMutableArray arrayWithObject:inFormat]; [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; diff --git a/jdk/src/macosx/native/sun/awt/CCursorManager.m b/jdk/src/macosx/native/sun/awt/CCursorManager.m index 601ea91e782..232a31621ac 100644 --- a/jdk/src/macosx/native/sun/awt/CCursorManager.m +++ b/jdk/src/macosx/native/sun/awt/CCursorManager.m @@ -74,7 +74,6 @@ Java_sun_lwawt_macosx_CCursorManager_nativeSetBuiltInCursor (JNIEnv *env, jclass class, jint type, jstring name) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSString *cursorName = JNFJavaToNSString(env, name); SEL cursorSelector = (type == sun_lwawt_macosx_CCursorManager_NAMED_CURSOR) ? lookupCursorSelectorForName(cursorName) : lookupCursorSelectorForType(type); @@ -87,9 +86,7 @@ AWT_ASSERT_NOT_APPKIT_THREAD; [JNFException raise:env as:kNoSuchMethodException reason:"missing NSCursor selector"]; } - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ setCursorOnAppKitThread([[NSCursor class] performSelector:cursorSelector]); }]; @@ -101,12 +98,9 @@ Java_sun_lwawt_macosx_CCursorManager_nativeSetCustomCursor (JNIEnv *env, jclass class, jlong imgPtr, jdouble x, jdouble y) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSImage *image = (NSImage *)jlong_to_ptr(imgPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ NSCursor *cursor = [[NSCursor alloc] initWithImage:image hotSpot:(NSPoint){ x, y }]; setCursorOnAppKitThread(cursor); @@ -127,8 +121,6 @@ JNF_COCOA_ENTER(env); __block NSPoint pt = NSZeroPoint; [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - AWT_ASSERT_APPKIT_THREAD; - pt = ConvertNSScreenPoint(env, [NSEvent mouseLocation]); }]; @@ -144,13 +136,11 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CCursorManager_nativeSetAllowsCursorSetInBackground (JNIEnv *env, jclass class, jboolean allows) { - JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; SEL allowsSetInBackground_SEL = @selector(javaSetAllowsCursorSetInBackground:); if ([[NSCursor class] respondsToSelector:allowsSetInBackground_SEL]) { - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ NSMethodSignature *allowsSetInBackground_sig = [[NSCursor class] methodSignatureForSelector:allowsSetInBackground_SEL]; NSInvocation *invocation = diff --git a/jdk/src/macosx/native/sun/awt/CDesktopPeer.m b/jdk/src/macosx/native/sun/awt/CDesktopPeer.m index af9f3192d91..9dd121059af 100644 --- a/jdk/src/macosx/native/sun/awt/CDesktopPeer.m +++ b/jdk/src/macosx/native/sun/awt/CDesktopPeer.m @@ -36,8 +36,6 @@ JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CDesktopPeer__1lsOpenURI (JNIEnv *env, jclass clz, jstring uri) { - // AWT_ASSERT_ANY_THREAD - OSStatus status = noErr; JNF_COCOA_ENTER(env); @@ -63,8 +61,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CDesktopPeer__1lsOpenFile (JNIEnv *env, jclass clz, jstring jpath, jboolean print) { - // AWT_ASSERT_ANY_THREAD - OSStatus status = noErr; JNF_COCOA_ENTER(env); diff --git a/jdk/src/macosx/native/sun/awt/CDragSourceContextPeer.m b/jdk/src/macosx/native/sun/awt/CDragSourceContextPeer.m index e2fedfe35df..46788795f45 100644 --- a/jdk/src/macosx/native/sun/awt/CDragSourceContextPeer.m +++ b/jdk/src/macosx/native/sun/awt/CDragSourceContextPeer.m @@ -46,7 +46,7 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDragSourceContextPeer_createNativ __block CDragSource* dragSource = nil; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ dragSource = [[CDragSource alloc] init:jthis component:jcomponent peer:jpeer control:controlObj transferable:jtransferable triggerEvent:jtrigger dragPosX:jdragposx dragPosY:jdragposy modifiers:jextmodifiers clickCount:jclickcount timeStamp:jtimestamp @@ -103,7 +103,7 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDragSourceContextPeer_setNativeCursor (JNIEnv *env, jobject jthis, jlong nativeDragSourceVal, jobject jcursor, jint jcursortype) { - AWT_ASSERT_NOT_APPKIT_THREAD; + //AWT_ASSERT_NOT_APPKIT_THREAD; //JNF_COCOA_ENTER(env); // jobject gCursor = JNFNewGlobalRef(env, jcursor); diff --git a/jdk/src/macosx/native/sun/awt/CImage.m b/jdk/src/macosx/native/sun/awt/CImage.m index 330e9943f62..9bd56da3db6 100644 --- a/jdk/src/macosx/native/sun/awt/CImage.m +++ b/jdk/src/macosx/native/sun/awt/CImage.m @@ -108,7 +108,6 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArra jlong result = 0L; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); if (imageRep) { @@ -139,7 +138,6 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArra jlong result = 0L; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; jsize num = (*env)->GetArrayLength(env, buffers); NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num]; @@ -187,7 +185,6 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIcon NSImage *image = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; IconRef iconRef; if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) { @@ -212,7 +209,6 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFile NSImage *image = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; NSString *path = JNFNormalizedNSStringForPath(env, file); image = [[NSImage alloc] initByReferencingFile:path]; @@ -234,10 +230,9 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFr __block NSImage *image = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; NSString *path = JNFNormalizedNSStringForPath(env, file); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ image = [[NSWorkspace sharedWorkspace] iconForFile:path]; [image setScalesWhenResized:TRUE]; if (image) CFRetain(image); // GC @@ -259,7 +254,6 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImag NSImage *image = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; image = [NSImage imageNamed:JNFJavaToNSString(env, name)]; if (image) CFRetain(image); // GC @@ -278,7 +272,6 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint w, jint h) { JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); @@ -301,7 +294,6 @@ JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize jobject size = NULL; JNF_COCOA_ENTER(env); -AWT_ASSERT_ANY_THREAD; size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); diff --git a/jdk/src/macosx/native/sun/awt/CInputMethod.m b/jdk/src/macosx/native/sun/awt/CInputMethod.m index 764e2db534d..39a66c7242d 100644 --- a/jdk/src/macosx/native/sun/awt/CInputMethod.m +++ b/jdk/src/macosx/native/sun/awt/CInputMethod.m @@ -153,7 +153,7 @@ JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeGetCurrentInp __block NSString *keyboardInfo = NULL; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ keyboardInfo = [inputMethodController performSelector:@selector(currentInputMethodName)]; [keyboardInfo retain]; }]; @@ -177,7 +177,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeNotifyPeer JNF_COCOA_ENTER(env); AWTView *view = (AWTView *)jlong_to_ptr(nativePeer); JNFJObjectWrapper *inputMethodWrapper = [[JNFJObjectWrapper alloc] initWithJObject:inputMethod withEnv:env]; - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [CInputMethod _nativeNotifyPeerWithView:view inputMethod:inputMethodWrapper]; }]; @@ -196,7 +196,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeEndComposition JNF_COCOA_ENTER(env); AWTView *view = (AWTView *)jlong_to_ptr(nativePeer); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [CInputMethod _nativeEndComposition:view]; }]; @@ -216,7 +216,7 @@ JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethod_getNativeLocale __block NSString *isoAbbreviation; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ isoAbbreviation = (NSString *) [inputMethodController performSelector:@selector(currentInputMethodLocale)]; [isoAbbreviation retain]; }]; @@ -259,7 +259,7 @@ JNF_COCOA_ENTER(env); NSString *localeStr = JNFJavaToNSString(env, locale); [localeStr retain]; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [CInputMethod setKeyboardLayout:localeStr]; }]; @@ -293,7 +293,7 @@ JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethodDescriptor_nativeGet __block NSArray *selectableArray = nil; JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ selectableArray = (NSArray *)[inputMethodController performSelector:@selector(availableInputMethodLocales)]; [selectableArray retain]; }]; diff --git a/jdk/src/macosx/native/sun/awt/CMenu.m b/jdk/src/macosx/native/sun/awt/CMenu.m index 32a9d5b7e12..e6325c2c3db 100644 --- a/jdk/src/macosx/native/sun/awt/CMenu.m +++ b/jdk/src/macosx/native/sun/awt/CMenu.m @@ -55,12 +55,10 @@ AWT_ASSERT_APPKIT_THREAD; //- (void)finalize { [super finalize]; } - (void)addJavaSubmenu:(CMenu *)submenu { -AWT_ASSERT_NOT_APPKIT_THREAD; [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:submenu waitUntilDone:YES awtMode:YES]; } - (void)addJavaMenuItem:(CMenuItem *)theMenuItem { -AWT_ASSERT_NOT_APPKIT_THREAD; [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:theMenuItem waitUntilDone:YES awtMode:YES]; } @@ -70,7 +68,6 @@ AWT_ASSERT_APPKIT_THREAD; } - (void)setJavaMenuTitle:(NSString *)title { -AWT_ASSERT_NOT_APPKIT_THREAD; if (title) { [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) onObject:self withObject:title waitUntilDone:YES awtMode:YES]; @@ -95,7 +92,6 @@ AWT_ASSERT_APPKIT_THREAD; } - (void)deleteJavaItem:(jint)index { -AWT_ASSERT_NOT_APPKIT_THREAD; [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; } diff --git a/jdk/src/macosx/native/sun/awt/CMenuComponent.m b/jdk/src/macosx/native/sun/awt/CMenuComponent.m index 9787625a751..4f9fc593e11 100644 --- a/jdk/src/macosx/native/sun/awt/CMenuComponent.m +++ b/jdk/src/macosx/native/sun/awt/CMenuComponent.m @@ -80,10 +80,10 @@ Java_sun_lwawt_macosx_CMenuComponent_nativeDispose { JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThread:@selector(disposer) - on:((id)jlong_to_ptr(menuItemObj)) - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(disposer) + on:((id)jlong_to_ptr(menuItemObj)) + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } diff --git a/jdk/src/macosx/native/sun/awt/CMenuItem.m b/jdk/src/macosx/native/sun/awt/CMenuItem.m index 663860d7ff6..2281d8bcd95 100644 --- a/jdk/src/macosx/native/sun/awt/CMenuItem.m +++ b/jdk/src/macosx/native/sun/awt/CMenuItem.m @@ -104,7 +104,6 @@ JNF_COCOA_EXIT(env); } - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers { -AWT_ASSERT_NOT_APPKIT_THREAD; NSUInteger modifierMask = 0; @@ -126,8 +125,7 @@ AWT_ASSERT_NOT_APPKIT_THREAD; modifierMask = JavaModifiersToNsKeyModifiers(modifiers, NO); } - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [fMenuItem setKeyEquivalent:theKeyEquivalent]; [fMenuItem setKeyEquivalentModifierMask:modifierMask]; [fMenuItem setTitle:theLabel]; @@ -135,32 +133,23 @@ AWT_ASSERT_NOT_APPKIT_THREAD; } - (void) setJavaImage:(NSImage *)theImage { -AWT_ASSERT_NOT_APPKIT_THREAD; - - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setImage:theImage]; }]; } - (void) setJavaToolTipText:(NSString *)theText { -AWT_ASSERT_NOT_APPKIT_THREAD; - - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setToolTip:theText]; }]; } - (void)setJavaEnabled:(BOOL) enabled { -AWT_ASSERT_NOT_APPKIT_THREAD; - - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ @synchronized(self) { fIsEnabled = enabled; @@ -173,7 +162,6 @@ AWT_ASSERT_NOT_APPKIT_THREAD; } - (BOOL)isEnabled { - // AWT_ASSERT_ANY_THREAD; BOOL enabled = NO; @synchronized(self) { @@ -184,11 +172,8 @@ AWT_ASSERT_NOT_APPKIT_THREAD; - (void)setJavaState:(BOOL)newState { -AWT_ASSERT_NOT_APPKIT_THREAD; - - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ -AWT_ASSERT_APPKIT_THREAD; + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setState:(newState ? NSOnState : NSOffState)]; }]; } diff --git a/jdk/src/macosx/native/sun/awt/CPopupMenu.m b/jdk/src/macosx/native/sun/awt/CPopupMenu.m index 49f4ceb9384..746bf44f785 100644 --- a/jdk/src/macosx/native/sun/awt/CPopupMenu.m +++ b/jdk/src/macosx/native/sun/awt/CPopupMenu.m @@ -64,7 +64,7 @@ JNF_COCOA_ENTER(env); jobject cPeerObjGlobal = JNFNewGlobalRef(env, peer); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ aCPopupMenu = [[CPopupMenu alloc] initWithPeer:cPeerObjGlobal]; CFRetain(aCPopupMenu); [aCPopupMenu release]; @@ -82,7 +82,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPopupMenu_nativeShowPopupMenu CPopupMenu* cPopupMenu = (CPopupMenu*)jlong_to_ptr(menuPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ NSPoint loc = ConvertNSScreenPoint(env, NSMakePoint(x, y)); [[cPopupMenu menu] popUpMenuPositioningItem: nil diff --git a/jdk/src/macosx/native/sun/awt/CTrayIcon.m b/jdk/src/macosx/native/sun/awt/CTrayIcon.m index a69995f84aa..fbc711534e9 100644 --- a/jdk/src/macosx/native/sun/awt/CTrayIcon.m +++ b/jdk/src/macosx/native/sun/awt/CTrayIcon.m @@ -303,10 +303,9 @@ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CTrayIcon_nativeCreate __block AWTTrayIcon *trayIcon = nil; JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; jobject thePeer = JNFNewGlobalRef(env, peer); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ trayIcon = [[AWTTrayIcon alloc] initWithPeer:thePeer]; }]; @@ -334,11 +333,10 @@ JNIEXPORT void JNICALL Java_java_awt_TrayIcon_initIDs JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTrayIcon_nativeSetToolTip (JNIEnv *env, jobject self, jlong model, jstring jtooltip) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; AWTTrayIcon *icon = jlong_to_ptr(model); NSString *tooltip = JNFJavaToNSString(env, jtooltip); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [icon setTooltip:tooltip]; }]; @@ -353,10 +351,9 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTrayIcon_setNativeImage (JNIEnv *env, jobject self, jlong model, jlong imagePtr, jboolean autosize) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; AWTTrayIcon *icon = jlong_to_ptr(model); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [icon setImage:jlong_to_ptr(imagePtr) sizing:autosize]; }]; @@ -369,13 +366,10 @@ Java_sun_lwawt_macosx_CTrayIcon_nativeGetIconLocation jobject jpt = NULL; JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; __block NSPoint pt = NSZeroPoint; AWTTrayIcon *icon = jlong_to_ptr(model); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ NSPoint loc = [icon getLocationOnScreen]; pt = ConvertNSScreenPoint(env, loc); }]; diff --git a/jdk/src/macosx/native/sun/awt/CWrapper.m b/jdk/src/macosx/native/sun/awt/CWrapper.m index eb047c5bc82..538a0c3f1ff 100644 --- a/jdk/src/macosx/native/sun/awt/CWrapper.m +++ b/jdk/src/macosx/native/sun/awt/CWrapper.m @@ -46,7 +46,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSObject_release JNF_COCOA_ENTER(env); id obj = (id)jlong_to_ptr(objectPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ CFRelease(obj); }]; @@ -66,10 +66,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_makeKeyAndOrderFront JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(makeKeyAndOrderFront:) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(makeKeyAndOrderFront:) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -86,10 +86,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_makeKeyWindow JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(makeKeyWindow) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(makeKeyWindow) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -106,10 +106,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_makeMainWindow JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(makeMainWindow) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(makeMainWindow) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -128,7 +128,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_canBecomeMainWindow JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ canBecomeMainWindow = [window canBecomeMainWindow]; }]; @@ -151,7 +151,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_isKeyWindow JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ isKeyWindow = [window isKeyWindow]; }]; @@ -172,10 +172,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_orderFront JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(orderFront:) - on:window - withObject:window - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(orderFront:) + on:window + withObject:window + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -192,10 +192,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_orderOut JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(orderOut:) - on:window - withObject:window - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(orderOut:) + on:window + withObject:window + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -212,10 +212,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_orderFrontRegardless JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(orderFrontRegardless) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(orderFrontRegardless) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -233,7 +233,7 @@ JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); NSWindow *relativeTo = (NSWindow *)jlong_to_ptr(relativeToPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window orderWindow:(NSWindowOrderingMode)order relativeTo:[relativeTo windowNumber]]; }]; @@ -267,7 +267,7 @@ JNF_COCOA_ENTER(env); initLevels(); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window setLevel: LEVELS[level]]; }]; } else { @@ -290,7 +290,7 @@ JNF_COCOA_ENTER(env); NSWindow *parent = (NSWindow *)jlong_to_ptr(parentPtr); NSWindow *child = (NSWindow *)jlong_to_ptr(childPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [parent addChildWindow:child ordered:order]; }]; @@ -310,10 +310,10 @@ JNF_COCOA_ENTER(env); AWTWindow *parent = (AWTWindow *)jlong_to_ptr(parentPtr); AWTWindow *child = (AWTWindow *)jlong_to_ptr(childPtr); - [JNFRunLoop performOnMainThread:@selector(removeChildWindow:) - on:parent - withObject:child - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(removeChildWindow:) + on:parent + withObject:child + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -331,7 +331,7 @@ JNF_COCOA_ENTER(env); AWTWindow *window = (AWTWindow *)jlong_to_ptr(windowPtr); NSRect frame = NSMakeRect(x, y, w, h); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window setFrame:frame display:display]; }]; @@ -350,7 +350,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_setAlphaValue JNF_COCOA_ENTER(env); AWTWindow *window = (AWTWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window setAlphaValue:(CGFloat)alpha]; }]; @@ -369,7 +369,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_setOpaque JNF_COCOA_ENTER(env); AWTWindow *window = (AWTWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window setOpaque:(BOOL)opaque]; }]; @@ -389,7 +389,7 @@ JNF_COCOA_ENTER(env); AWTWindow *window = (AWTWindow *)jlong_to_ptr(windowPtr); NSColor *color = (NSColor *)jlong_to_ptr(colorPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [window setBackgroundColor:color]; }]; @@ -410,7 +410,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_screen JNF_COCOA_ENTER(env); AWTWindow *window = (AWTWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ const NSScreen *screen = [window screen]; CFRetain(screen); // GC screenPtr = ptr_to_jlong(screen); @@ -432,10 +432,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_miniaturize JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(miniaturize:) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(miniaturize:) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -452,10 +452,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_deminiaturize JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(deminiaturize:) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(deminiaturize:) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -472,10 +472,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSWindow_zoom JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); - [JNFRunLoop performOnMainThread:@selector(zoom:) - on:window - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(zoom:) + on:window + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -493,10 +493,10 @@ JNF_COCOA_ENTER(env); NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr); NSResponder *responder = (NSResponder *)jlong_to_ptr(responderPtr); - [JNFRunLoop performOnMainThread:@selector(makeFirstResponder:) - on:window - withObject:responder - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(makeFirstResponder:) + on:window + withObject:responder + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -514,7 +514,7 @@ JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); NSView *subview = (NSView *)jlong_to_ptr(subviewPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [view addSubview:subview]; }]; @@ -533,10 +533,10 @@ Java_sun_lwawt_macosx_CWrapper_00024NSView_removeFromSuperview JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThread:@selector(removeFromSuperview) - on:view - withObject:nil - waitUntilDone:NO]; + [ThreadUtilities performOnMainThread:@selector(removeFromSuperview) + on:view + withObject:nil + waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -553,7 +553,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSView_setFrame JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [view setFrame:NSMakeRect(x, y, w, h)]; }]; @@ -576,7 +576,7 @@ JNF_COCOA_ENTER(env); __block NSRect rect = NSZeroRect; NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ rect = [view frame]; }]; @@ -599,7 +599,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSView_enterFullScreenMode JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ NSScreen *screen = [[view window] screen]; NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], NSFullScreenModeAllScreens, nil]; [view enterFullScreenMode:screen withOptions:opts]; @@ -620,7 +620,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSView_exitFullScreenMode JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [view exitFullScreenModeWithOptions:nil]; }]; @@ -641,7 +641,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSView_window JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ windowPtr = ptr_to_jlong([view window]); }]; @@ -655,14 +655,14 @@ JNF_COCOA_EXIT(env); * Method: setHidden * Signature: (JZ)V */ -JNIEXPORT jlong JNICALL +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CWrapper_00024NSView_setHidden (JNIEnv *env, jclass cls, jlong viewPtr, jboolean toHide) { JNF_COCOA_ENTER(env); NSView *view = (NSView *)jlong_to_ptr(viewPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [view setHidden:(BOOL)toHide]; }]; @@ -686,7 +686,7 @@ JNF_COCOA_ENTER(env); __block NSRect rect = NSZeroRect; NSScreen *screen = (NSScreen *)jlong_to_ptr(screenPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ rect = [screen frame]; }]; @@ -713,7 +713,7 @@ JNF_COCOA_ENTER(env); __block NSRect rect = NSZeroRect; NSScreen *screen = (NSScreen *)jlong_to_ptr(screenPtr); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ rect = [screen visibleFrame]; }]; @@ -737,7 +737,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSScreen_screenByDisplayId JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ NSArray *screens = [NSScreen screens]; for (NSScreen *screen in screens) { NSDictionary *screenInfo = [screen deviceDescription]; @@ -768,7 +768,7 @@ Java_sun_lwawt_macosx_CWrapper_00024NSColor_clearColor JNF_COCOA_ENTER(env); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ clearColorPtr = ptr_to_jlong([NSColor clearColor]); }]; diff --git a/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m b/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m index 61ba619af40..f886c4afbe1 100644 --- a/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m +++ b/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m @@ -1147,7 +1147,6 @@ static NSObject *sAttributeNamesLOCK = nil; JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged (JNIEnv *env, jobject jthis) { - AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) onObject:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO awtMode:NO]; @@ -1164,7 +1163,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged (JNIEnv *env, jclass jklass, jlong element) { - AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(postValueChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; JNF_COCOA_EXIT(env); @@ -1178,7 +1176,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged (JNIEnv *env, jclass jklass, jlong element) { - AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; JNF_COCOA_EXIT(env); @@ -1193,7 +1190,6 @@ JNF_COCOA_EXIT(env); JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem (JNIEnv *env, jclass jklass, jlong element) { - AWT_ASSERT_NOT_APPKIT_THREAD; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; JNF_COCOA_EXIT(env); diff --git a/jdk/src/macosx/native/sun/awt/LWCToolkit.m b/jdk/src/macosx/native/sun/awt/LWCToolkit.m index b58cfc0627d..45c546181f0 100644 --- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m +++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m @@ -415,13 +415,9 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive JNF_COCOA_ENTER(env); - if ([NSThread isMainThread]) { + [ThreadUtilities performOnMainThreadWaiting:YES block:^() { active = (jboolean)[NSRunningApplication currentApplication].active; - } else { - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^() { - active = (jboolean)[NSRunningApplication currentApplication].active; - }]; - } + }]; JNF_COCOA_EXIT(env); diff --git a/jdk/src/macosx/native/sun/awt/awt.m b/jdk/src/macosx/native/sun/awt/awt.m index 8ca56bd117c..ea684ed0808 100644 --- a/jdk/src/macosx/native/sun/awt/awt.m +++ b/jdk/src/macosx/native/sun/awt/awt.m @@ -42,6 +42,15 @@ // The symbol is defined in libosxapp.dylib (ThreadUtilities.m) extern JavaVM *jvm; +// Indicates if AWT is running embedded (in SWT, FX, elsewhere) +static BOOL isEmbedded = NO; + +// Indicates that the app has been started with -XstartOnFirstThread +// (directly or via WebStart settings), and AWT should not run its +// own event loop in this mode. Even if a loop isn't running yet, +// we expect an embedder (e.g. SWT) to start it some time later. +static BOOL forceEmbeddedMode = NO; + static bool ShouldPrintVerboseDebugging() { static int debug = -1; if (debug == -1) { @@ -63,31 +72,29 @@ static void AWT_NSUncaughtExceptionHandler(NSException *exception); static CFRunLoopObserverRef busyObserver = NULL; static CFRunLoopObserverRef notBusyObserver = NULL; -static void setUpAWTAppKit(BOOL swt_mode, BOOL headless) { -AWT_ASSERT_APPKIT_THREAD; +static void setUpAWTAppKit() +{ BOOL verbose = ShouldPrintVerboseDebugging(); if (verbose) AWT_DEBUG_LOG(@"setting up busy observers"); - JNIEnv *env = [ThreadUtilities getJNIEnv]; - // Add CFRunLoopObservers to call into AWT so that AWT knows that the // AWT thread (which is the AppKit main thread) is alive. This way AWT // will not automatically shutdown. busyObserver = CFRunLoopObserverCreate( - NULL, // CFAllocator - kCFRunLoopAfterWaiting, // CFOptionFlags - true, // repeats - NSIntegerMax, // order - &BusyObserver, // CFRunLoopObserverCallBack - NULL); // CFRunLoopObserverContext + NULL, // CFAllocator + kCFRunLoopAfterWaiting, // CFOptionFlags + true, // repeats + NSIntegerMax, // order + &BusyObserver, // CFRunLoopObserverCallBack + NULL); // CFRunLoopObserverContext notBusyObserver = CFRunLoopObserverCreate( - NULL, // CFAllocator - kCFRunLoopBeforeWaiting, // CFOptionFlags - true, // repeats - NSIntegerMin, // order - &NotBusyObserver, // CFRunLoopObserverCallBack - NULL); // CFRunLoopObserverContext + NULL, // CFAllocator + kCFRunLoopBeforeWaiting, // CFOptionFlags + true, // repeats + NSIntegerMin, // order + &NotBusyObserver, // CFRunLoopObserverCallBack + NULL); // CFRunLoopObserverContext CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop]; CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode); @@ -95,29 +102,33 @@ AWT_ASSERT_APPKIT_THREAD; CFRelease(busyObserver); CFRelease(notBusyObserver); - - if (!headless) setBusy(YES); + + setBusy(YES); +} + +static void setUpAppKitThreadName() +{ + BOOL verbose = ShouldPrintVerboseDebugging(); + JNIEnv *env = [ThreadUtilities getJNIEnv]; // Set the java name of the AppKit main thread appropriately. jclass threadClass = NULL; jstring name = NULL; jobject curThread = NULL; - if (!swt_mode) { - threadClass = (*env)->FindClass(env, "java/lang/Thread"); - if (threadClass == NULL || (*env)->ExceptionCheck(env)) goto cleanup; - jmethodID currentThreadID = (*env)->GetStaticMethodID(env, threadClass, "currentThread", "()Ljava/lang/Thread;"); - if (currentThreadID == NULL || (*env)->ExceptionCheck(env)) goto cleanup; - jmethodID setName = (*env)->GetMethodID(env, threadClass, "setName", "(Ljava/lang/String;)V"); - if (setName == NULL || (*env)->ExceptionCheck(env)) goto cleanup; + threadClass = (*env)->FindClass(env, "java/lang/Thread"); + if (threadClass == NULL || (*env)->ExceptionCheck(env)) goto cleanup; + jmethodID currentThreadID = (*env)->GetStaticMethodID(env, threadClass, "currentThread", "()Ljava/lang/Thread;"); + if (currentThreadID == NULL || (*env)->ExceptionCheck(env)) goto cleanup; + jmethodID setName = (*env)->GetMethodID(env, threadClass, "setName", "(Ljava/lang/String;)V"); + if (setName == NULL || (*env)->ExceptionCheck(env)) goto cleanup; - curThread = (*env)->CallStaticObjectMethod(env, threadClass, currentThreadID); // AWT_THREADING Safe (known object) - if (curThread == NULL || (*env)->ExceptionCheck(env)) goto cleanup; - name = (*env)->NewStringUTF(env, "AWT-AppKit"); - if (name == NULL || (*env)->ExceptionCheck(env)) goto cleanup; - (*env)->CallVoidMethod(env, curThread, setName, name); // AWT_THREADING Safe (known object) - if ((*env)->ExceptionCheck(env)) goto cleanup; - } + curThread = (*env)->CallStaticObjectMethod(env, threadClass, currentThreadID); // AWT_THREADING Safe (known object) + if (curThread == NULL || (*env)->ExceptionCheck(env)) goto cleanup; + name = (*env)->NewStringUTF(env, "AWT-AppKit"); + if (name == NULL || (*env)->ExceptionCheck(env)) goto cleanup; + (*env)->CallVoidMethod(env, curThread, setName, name); // AWT_THREADING Safe (known object) + if ((*env)->ExceptionCheck(env)) goto cleanup; cleanup: if (threadClass != NULL) { @@ -134,14 +145,10 @@ cleanup: (*env)->ExceptionClear(env); } - // Add the exception handler of last resort - NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler); - if (verbose) AWT_DEBUG_LOG(@"finished setting thread name"); } - // Returns true if java believes it is running headless BOOL isHeadless(JNIEnv *env) { // Just access the property directly, instead of using GraphicsEnvironment.isHeadless. @@ -200,7 +207,7 @@ static void AWT_NSUncaughtExceptionHandler(NSException *exception) { // This is an empty Obj-C object just so that -peformSelectorOnMainThread can be used. @interface AWTStarter : NSObject { } -+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart; ++ (void)start:(BOOL)headless; - (void)starter:(NSArray*)args; + (void)appKitIsRunning:(id)arg; @end @@ -242,7 +249,7 @@ AWT_ASSERT_APPKIT_THREAD; if (verbose) AWT_DEBUG_LOG(@"finished messaging AppKit started"); } -+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart ++ (void)start:(BOOL)headless { BOOL verbose = ShouldPrintVerboseDebugging(); @@ -258,7 +265,7 @@ AWT_ASSERT_APPKIT_THREAD; BOOL onMainThread = (pthread_main_np() != 0); if (verbose) { - NSString *msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d swtMode:%d swtModeForWebStart:%d] { onMainThread:%d }", headless, swtMode, swtModeForWebStart, onMainThread]; + NSString *msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d] { onMainThread:%d }", headless, onMainThread]; AWT_DEBUG_LOG(msg); } @@ -280,9 +287,7 @@ AWT_ASSERT_APPKIT_THREAD; NSArray * args = [NSArray arrayWithObjects: [NSNumber numberWithBool: onMainThread], - [NSNumber numberWithBool: swtMode], [NSNumber numberWithBool: headless], - [NSNumber numberWithBool: swtModeForWebStart], [NSNumber numberWithBool: verbose], nil]; @@ -310,39 +315,38 @@ AWT_ASSERT_APPKIT_THREAD; // Don't set the delegate until the NSApplication has been created and // its finishLaunching has initialized it. // ApplicationDelegate is the support code for com.apple.eawt. - void (^setDelegateBlock)() = ^(){ + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ OSXAPP_SetApplicationDelegate([ApplicationDelegate sharedDelegate]); - }; - if (onMainThread) { - setDelegateBlock(); - } else { - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:setDelegateBlock]; - } + }]; } - (void)starter:(NSArray*)args { NSAutoreleasePool *pool = [NSAutoreleasePool new]; BOOL onMainThread = [[args objectAtIndex:0] boolValue]; - BOOL swtMode = [[args objectAtIndex:1] boolValue]; - BOOL headless = [[args objectAtIndex:2] boolValue]; - BOOL swtModeForWebStart = [[args objectAtIndex:3] boolValue]; - BOOL verbose = [[args objectAtIndex:4] boolValue]; + BOOL headless = [[args objectAtIndex:1] boolValue]; + BOOL verbose = [[args objectAtIndex:2] boolValue]; BOOL wasOnMainThread = onMainThread; - setUpAWTAppKit(swtMode, headless); + // Add the exception handler of last resort + NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler); // Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return. if (headless) { - BOOL didBecomeDaemon = [AWTStarter markAppAsDaemon]; + if (!forceEmbeddedMode) { + setUpAppKitThreadName(); + } + [AWTStarter markAppAsDaemon]; return; } - if (swtMode || swtModeForWebStart) { + if (forceEmbeddedMode) { if (verbose) NSLog(@"in SWT or SWT/WebStart mode"); - // The SWT should call NSApplicationLoad, but they don't know a priori that they will be using the AWT, so they don't. + // Init a default NSApplication instance instead of the NSApplicationAWT. + // Note that [NSApp isRunning] will return YES after that, though + // this behavior isn't specified anywhere. We rely on that. NSApplicationLoad(); } @@ -351,6 +355,13 @@ AWT_ASSERT_APPKIT_THREAD; // and -[NSApplication isRunning] returns YES, AWT is embedded inside another // AppKit Application. NSApplication *app = [NSApplicationAWT sharedApplication]; + isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]]; + + if (!isEmbedded) { + // Install run loop observers and set the AppKit Java thread name + setUpAWTAppKit(); + setUpAppKitThreadName(); + } // AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent. if (![app isRunning]) { @@ -360,17 +371,11 @@ AWT_ASSERT_APPKIT_THREAD; [NSApplicationAWT runAWTLoopWithApp: app]; } else { // We're either embedded, or showing a splash screen - if (![NSApp isKindOfClass:[NSApplicationAWT class]]) { + if (isEmbedded) { if (verbose) AWT_DEBUG_LOG(@"running embedded"); - // Since we're embedded, no need to be swamping the runloop with the observers. - CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop]; - CFRunLoopRemoveObserver(runLoop, busyObserver, kCFRunLoopDefaultMode); - CFRunLoopRemoveObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode); // We don't track if the runloop is busy, so set it free to let AWT finish when it needs setBusy(NO); - busyObserver = NULL; - notBusyObserver = NULL; } else { if (verbose) AWT_DEBUG_LOG(@"running after showing a splash screen"); } @@ -408,49 +413,28 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_VERSION_1_4; } - // The following is true when AWT is attempting to connect to the window server - // when it isn't set up properly to do so. - // BOOL AWTLoadFailure = YES; For now we are skipping this check so i'm commenting out this variable as unused JNF_COCOA_ENTER(env); - // If -XstartOnFirstThread was used at invocation time, an environment variable will be set. - // (See java_md.c for the matching setenv call.) When that happens, we assume the SWT will be in use. - BOOL swt_compatible_mode = NO; - + // Launcher sets this env variable if -XstartOnFirstThread is specified char envVar[80]; snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid()); if (getenv(envVar) != NULL) { - swt_compatible_mode = YES; + forceEmbeddedMode = YES; unsetenv(envVar); } - BOOL swt_in_webstart = isSWTInWebStart(env); - BOOL headless = isHeadless(env); - - // Make sure we're on the right thread. If not, we still need the JNIEnv to throw an exception. - if (pthread_main_np() != 0 && !swt_compatible_mode && !headless) { - AWT_DEBUG_LOG(@"Apple AWT Java VM was loaded on first thread -- can't start AWT."); - [JNFException raise:env as:kInternalError reason:"Can't start the AWT because Java was started on the first thread. Make sure StartOnFirstThread is " - "not specified in your application's Info.plist or on the command line"]; - return JNI_VERSION_1_4; + if (isSWTInWebStart(env)) { + forceEmbeddedMode = YES; } + BOOL headless = isHeadless(env); + // We need to let Foundation know that this is a multithreaded application, if it isn't already. if (![NSThread isMultiThreaded]) { [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]; } -// if (swt_compatible_mode || headless || [AWTStarter isConnectedToWindowServer] || [AWTStarter isRemoteSession]) { -// No need in this check - we will try to launch AWTStarter anyways - to be able to run GUI application remotely -// AWTLoadFailure = NO; - - [AWTStarter start:headless swtMode:swt_compatible_mode swtModeForWebStart:swt_in_webstart]; - -// } - -/* if (AWTLoadFailure) { // We will not reach this code anyways - [JNFException raise:env as:kInternalError reason:"Can't connect to window server - not enough permissions."]; - } */ + [AWTStarter start:headless]; JNF_COCOA_EXIT(env); diff --git a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h index 0acde2f9aa6..c0d2054f6e3 100644 --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h @@ -98,8 +98,6 @@ do { \ } \ } while (0) -#define AWT_ASSERT_ANY_THREAD - #endif /* AWT_THREAD_ASSERTS_MESSAGES */ #ifdef AWT_THREAD_ASSERTS_WAIT @@ -114,15 +112,12 @@ do { \ while (pthread_main_np() != 0) {} \ } while (0) -#define AWT_ASSERT_ANY_THREAD - #endif /* AWT_THREAD_ASSERTS_WAIT */ #else /* AWT_THREAD_ASSERTS */ #define AWT_ASSERT_APPKIT_THREAD do {} while (0) #define AWT_ASSERT_NOT_APPKIT_THREAD do {} while (0) -#define AWT_ASSERT_ANY_THREAD #endif /* AWT_THREAD_ASSERTS */ // -------------------------------------------------------------------------- @@ -139,7 +134,10 @@ __attribute__((visibility("default"))) + (JNIEnv*)getJNIEnvUncached; + (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT; + +//Wrappers for the corresponding JNFRunLoop methods with a check for main thread + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; ++ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; @end void OSXAPP_SetJavaVM(JavaVM *vm); diff --git a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m index 0e40fc1a52b..0b42f1b5896 100644 --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m @@ -37,27 +37,13 @@ static JNIEnv *appKitEnv = NULL; static NSArray *sPerformModes = nil; static NSArray *sAWTPerformModes = nil; -static BOOL sCocoaComponentCompatibility = NO; -static NSTimeInterval sCocoaComponentCompatibilityTimeout = 0.5; static BOOL sLoggingEnabled = YES; #ifdef AWT_THREAD_ASSERTS_ENV_ASSERT int sAWTThreadAsserts = 0; #endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */ - -// This is for backward compatibility for those people using CocoaComponent -// Since we've flipped the AWT threading model for Tiger (10.4), all the rules -// for CocoaComponent are wrong. -// So for existing CocoaComponent users, we can't be synchronous. -// Making things totally asynchronous breaks a _lot_, so we try to be -// synchronous and time out after a little bit. -#define NOT_READY 0 -#define READY 1 -#define IN_PROGRESS 2 - BOOL sInPerformFromJava = NO; -NSUInteger sPerformCount = 0; // This class is used so that performSelectorOnMainThread can be // controlled a little more easily by us. It has 2 roles. @@ -73,8 +59,6 @@ NSUInteger sPerformCount = 0; - (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait; - (void) perform; -- (void) performCompatible; -- (void) _performCompatible:(NSConditionLock *)resultLock; @end @@ -113,8 +97,6 @@ NSUInteger sPerformCount = 0; sInPerformFromJava = YES; } - sPerformCount++; - // Actually do the work (cheat to avoid a method call) @try { objc_msgSend(fTarget, fSelector, fArg); @@ -128,69 +110,6 @@ NSUInteger sPerformCount = 0; } } } - -- (void) performCompatible { - // We check if we are on the AppKit thread because frequently, apps - // using CocoaComponent are doing things on the wrong thread! - if (pthread_main_np()) { - [fTarget performSelector:fSelector withObject:fArg]; - } else { - // Setup the lock - NSConditionLock *resultLock = - [[NSConditionLock alloc] initWithCondition:NOT_READY]; - - // Make sure that if we return early, nothing gets released out - // from under us - [resultLock retain]; - [fTarget retain]; - [fArg retain]; - [self retain]; - // Do an asynchronous perform to the main thread. - [self performSelectorOnMainThread:@selector(_performCompatible:) - withObject:resultLock waitUntilDone:NO modes:sAWTPerformModes]; - - // Wait for a little bit for it to finish - [resultLock lockWhenCondition:READY beforeDate:[NSDate dateWithTimeIntervalSinceNow:sCocoaComponentCompatibilityTimeout]]; - - // If the _performCompatible is actually in progress, - // we should let it finish - if ([resultLock condition] == IN_PROGRESS) { - [resultLock lockWhenCondition:READY]; - } - - if ([resultLock condition] == NOT_READY && sLoggingEnabled) { - NSLog(@"[Java CocoaComponent compatibility mode]: Operation timed out due to possible deadlock: selector '%@' on target '%@' with args '%@'", NSStringFromSelector(fSelector), fTarget, fArg); - } - - [resultLock unlock]; - [resultLock autorelease]; - } -} - -- (void) _performCompatible:(NSConditionLock *)resultLock { - // notify that the perform is in progress! - [resultLock lock]; - [resultLock unlockWithCondition:IN_PROGRESS]; - - sPerformCount++; - - // Actually do the work. - @try { - [fTarget performSelector:fSelector withObject:fArg]; - } @catch (NSException *e) { - NSLog(@"*** CPerformer: ignoring exception '%@' raised during performCompatible of selector '%@' on target '%@' with args '%@'", e, NSStringFromSelector(fSelector), fTarget, fArg); - } @finally { - // notify done! - [resultLock lock]; - [resultLock unlockWithCondition:READY]; - - // Clean up after ourselves - [resultLock autorelease]; - [fTarget autorelease]; - [fArg autorelease]; - [self autorelease]; - } -} @end @@ -236,13 +155,8 @@ AWT_ASSERT_APPKIT_THREAD; // java event thread without deadlocking. See CToolkit.invokeAndWait. + (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT { CPerformer *performer = [[CPerformer alloc] initWithTarget:target selector:aSelector arg:arg wait:wait]; - if (sCocoaComponentCompatibility && wait && inAWT) { - [performer performCompatible]; - [performer autorelease]; - } else { - [performer performSelectorOnMainThread:@selector(perform) withObject:nil waitUntilDone:wait modes:((inAWT) ? sAWTPerformModes : sPerformModes)]; // AWT_THREADING Safe (cover method) - [performer release]; - } + [performer performSelectorOnMainThread:@selector(perform) withObject:nil waitUntilDone:wait modes:((inAWT) ? sAWTPerformModes : sPerformModes)]; // AWT_THREADING Safe (cover method) + [performer release]; } + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { @@ -253,6 +167,14 @@ AWT_ASSERT_APPKIT_THREAD; } } ++ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait { + if ([NSThread isMainThread] && wait == YES) { + [target performSelector:aSelector withObject:arg]; + } else { + [JNFRunLoop performOnMainThread:aSelector on:target withObject:arg waitUntilDone:wait]; + } +} + @end diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 6fb52a4cd4a..1fe26b09f31 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -787,7 +787,6 @@ public class GTKLookAndFeel extends SynthLookAndFeel { "List.font", new FontLazyValue(Region.LIST), "List.rendererUseUIBorder", Boolean.FALSE, - "Menu.shortcutKeys", new int[] {KeyEvent.ALT_MASK}, "Menu.arrowIcon", new GTKStyle.GTKLazyValue( "com.sun.java.swing.plaf.gtk.GTKIconFactory", "getMenuArrowIcon"), diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index 923cd9d18b9..fdc6fa6210a 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -630,8 +630,10 @@ public class MotifLookAndFeel extends BasicLookAndFeel "Menu.menuPopupOffsetY", new Integer(0), "Menu.submenuPopupOffsetX", new Integer(-2), "Menu.submenuPopupOffsetY", new Integer(3), - "Menu.shortcutKeys", new int[] {KeyEvent.ALT_MASK, - KeyEvent.META_MASK}, + "Menu.shortcutKeys", new int[]{ + SwingUtilities2.getSystemMnemonicKeyMask(), + KeyEvent.META_MASK + }, "Menu.cancelMode", "hideMenuTree", "MenuBar.border", menuBarBorder, diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index 7d5e237948c..6213ac1e0c0 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -2619,13 +2619,15 @@ public class WindowsLookAndFeel extends BasicLookAndFeel private static class FocusColorProperty extends DesktopProperty { public FocusColorProperty () { - // Fallback value is never used bacause of the configureValue method doesn't return null + // Fallback value is never used because of the configureValue method doesn't return null super("win.3d.backgroundColor", Color.BLACK); } @Override protected Object configureValue(Object value) { - if (! ((Boolean)Toolkit.getDefaultToolkit().getDesktopProperty("win.highContrast.on")).booleanValue()){ + Object highContrastOn = Toolkit.getDefaultToolkit(). + getDesktopProperty("win.highContrast.on"); + if (highContrastOn == null || !((Boolean) highContrastOn).booleanValue()) { return Color.BLACK; } return Color.BLACK.equals(value) ? Color.WHITE : Color.BLACK; diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java index 1fbc2254d99..db5baf9610c 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java @@ -93,6 +93,11 @@ public class WindowsTreeUI extends BasicTreeUI { counter = endRow; } } + + if (testRect == null) { + return; + } + tree.scrollRectToVisible(new Rectangle(visRect.x, beginY, 1, testRect.y + testRect.height- beginY)); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index fd644bf759e..9e891fc7c87 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -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 @@ -177,6 +177,7 @@ class Attribute implements Comparable { define(sd, ATTR_CONTEXT_METHOD, "Synthetic", ""); define(sd, ATTR_CONTEXT_METHOD, "Deprecated", ""); define(sd, ATTR_CONTEXT_METHOD, "Exceptions", "NH[RCH]"); + define(sd, ATTR_CONTEXT_METHOD, "MethodParameters", "NB[RUNHI]"); //define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]"); define(sd, ATTR_CONTEXT_CODE, "StackMapTable", diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java index f3d5cec8e48..fdfb87dc136 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -1502,6 +1502,10 @@ class BandStructure { CPRefBand method_Exceptions_RC = method_attr_bands.newCPRefBand("method_Exceptions_RC", CONSTANT_Class); CPRefBand method_Signature_RS = method_attr_bands.newCPRefBand("method_Signature_RS", CONSTANT_Signature); MultiBand method_metadata_bands = method_attr_bands.newMultiBand("(method_metadata_bands)", UNSIGNED5); + // band for predefine method parameters + IntBand method_MethodParameters_NB = method_attr_bands.newIntBand("method_MethodParameters_NB", BYTE1); + CPRefBand method_MethodParameters_name_RUN = method_attr_bands.newCPRefBand("method_MethodParameters_name_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK); + IntBand method_MethodParameters_flag_I = method_attr_bands.newIntBand("method_MethodParameters_flag_I"); MultiBand class_attr_bands = class_bands.newMultiBand("(class_attr_bands)", UNSIGNED5); IntBand class_flags_hi = class_attr_bands.newIntBand("class_flags_hi"); @@ -1768,6 +1772,13 @@ class BandStructure { method_Exceptions_RC }, "Exceptions", "NH[RCH]"); + predefineAttribute(METHOD_ATTR_MethodParameters, ATTR_CONTEXT_METHOD, + new Band[]{ + method_MethodParameters_NB, + method_MethodParameters_name_RUN, + method_MethodParameters_flag_I + }, + "MethodParameters", "NB[RUNHI]"); assert(attrCodeEmpty == Package.attrCodeEmpty); predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD, new Band[] { method_Signature_RS }, diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java index b5c1d124ef6..15882624381 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -73,6 +73,9 @@ class Constants { public final static Package.Version JAVA7_PACKAGE_VERSION = Package.Version.of(170, 1); + public final static Package.Version JAVA8_PACKAGE_VERSION = + Package.Version.of(171, 0); + // upper limit, should point to the latest class version public final static Package.Version JAVA_MAX_CLASS_VERSION = JAVA8_MAX_CLASS_VERSION; @@ -158,6 +161,7 @@ class Constants { METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24, CLASS_ATTR_ClassFile_version = 24, METHOD_ATTR_AnnotationDefault = 25, + METHOD_ATTR_MethodParameters = 26, CODE_ATTR_StackMapTable = 0, // new in Java 6 CODE_ATTR_LineNumberTable = 1, CODE_ATTR_LocalVariableTable = 2, diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index 26bade85c5d..319b8793347 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -242,6 +242,7 @@ class PackageReader extends BandStructure { void checkArchiveVersion() throws IOException { Package.Version versionFound = null; for (Package.Version v : new Package.Version[] { + JAVA8_PACKAGE_VERSION, JAVA7_PACKAGE_VERSION, JAVA6_PACKAGE_VERSION, JAVA5_PACKAGE_VERSION @@ -252,7 +253,9 @@ class PackageReader extends BandStructure { } } if (versionFound == null) { - String expVer = JAVA7_PACKAGE_VERSION.toString() + String expVer = JAVA8_PACKAGE_VERSION.toString() + + "OR" + + JAVA7_PACKAGE_VERSION.toString() + " OR " + JAVA6_PACKAGE_VERSION.toString() + " OR " @@ -1516,6 +1519,9 @@ class PackageReader extends BandStructure { // method_metadata_bands // *method_Exceptions_N :UNSIGNED5 // *method_Exceptions_RC :UNSIGNED5 (cp_Class) + // *method_MethodParameters_NB: BYTE1 + // *method_MethodParameters_RUN: UNSIGNED5 (cp_Utf8) + // *method_MethodParameters_I: UNSIGNED5 (flag) // // code_attr_bands: // *code_flags :UNSIGNED5 diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index 78754b5c72b..e6990451135 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -142,12 +142,14 @@ class PackageWriter extends BandStructure { } else if (highV.equals(JAVA6_MAX_CLASS_VERSION) || (highV.equals(JAVA7_MAX_CLASS_VERSION) && !pkg.cp.haveExtraTags())) { // force down the package version if we have jdk7 classes without - // any Indy references, this is because jdk7 class file (52.0) without - // Indy is identical to jdk6 class file (51.0). + // any Indy references, this is because jdk7 class file (51.0) without + // Indy is identical to jdk6 class file (50.0). packageVersion = JAVA6_PACKAGE_VERSION; + } else if (highV.equals(JAVA7_MAX_CLASS_VERSION)) { + packageVersion = JAVA7_PACKAGE_VERSION; } else { // Normal case. Use the newest archive format, when available - packageVersion = JAVA7_PACKAGE_VERSION; + packageVersion = JAVA8_PACKAGE_VERSION; } if (verbose > 0) { diff --git a/jdk/src/share/classes/com/sun/net/httpserver/BasicAuthenticator.java b/jdk/src/share/classes/com/sun/net/httpserver/BasicAuthenticator.java index 781510a2cca..60ccd3ab73d 100644 --- a/jdk/src/share/classes/com/sun/net/httpserver/BasicAuthenticator.java +++ b/jdk/src/share/classes/com/sun/net/httpserver/BasicAuthenticator.java @@ -25,6 +25,8 @@ package com.sun.net.httpserver; +import java.util.Base64; + /** * BasicAuthenticator provides an implementation of HTTP Basic * authentication. It is an abstract class and must be extended @@ -68,7 +70,7 @@ public abstract class BasicAuthenticator extends Authenticator { if (sp == -1 || !auth.substring(0, sp).equals ("Basic")) { return new Authenticator.Failure (401); } - byte[] b = Base64.base64ToByteArray (auth.substring(sp+1)); + byte[] b = Base64.getDecoder().decode(auth.substring(sp+1)); String userpass = new String (b); int colon = userpass.indexOf (':'); String uname = userpass.substring (0, colon); @@ -102,208 +104,3 @@ public abstract class BasicAuthenticator extends Authenticator { public abstract boolean checkCredentials (String username, String password); } -class Base64 { - - /** - * Translates the specified byte array into a Base64 string as per - * Preferences.put(byte[]). - */ - static String byteArrayToBase64(byte[] a) { - return byteArrayToBase64(a, false); - } - - /** - * Translates the specified byte array into an "aternate representation" - * Base64 string. This non-standard variant uses an alphabet that does - * not contain the uppercase alphabetic characters, which makes it - * suitable for use in situations where case-folding occurs. - */ - static String byteArrayToAltBase64(byte[] a) { - return byteArrayToBase64(a, true); - } - - private static String byteArrayToBase64(byte[] a, boolean alternate) { - int aLen = a.length; - int numFullGroups = aLen/3; - int numBytesInPartialGroup = aLen - 3*numFullGroups; - int resultLen = 4*((aLen + 2)/3); - StringBuffer result = new StringBuffer(resultLen); - char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64); - - // Translate all full groups from byte array elements to Base64 - int inCursor = 0; - for (int i=0; i> 2]); - result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); - result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]); - result.append(intToAlpha[byte2 & 0x3f]); - } - - // Translate partial group if present - if (numBytesInPartialGroup != 0) { - int byte0 = a[inCursor++] & 0xff; - result.append(intToAlpha[byte0 >> 2]); - if (numBytesInPartialGroup == 1) { - result.append(intToAlpha[(byte0 << 4) & 0x3f]); - result.append("=="); - } else { - // assert numBytesInPartialGroup == 2; - int byte1 = a[inCursor++] & 0xff; - result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); - result.append(intToAlpha[(byte1 << 2)&0x3f]); - result.append('='); - } - } - // assert inCursor == a.length; - // assert result.length() == resultLen; - return result.toString(); - } - - /** - * This array is a lookup table that translates 6-bit positive integer - * index values into their "Base64 Alphabet" equivalents as specified - * in Table 1 of RFC 2045. - */ - private static final char intToBase64[] = { - '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', - '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', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * This array is a lookup table that translates 6-bit positive integer - * index values into their "Alternate Base64 Alphabet" equivalents. - * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045. - * This alternate alphabet does not use the capital letters. It is - * designed for use in environments where "case folding" occurs. - */ - private static final char intToAltBase64[] = { - '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':', - ';', '<', '>', '@', '[', ']', '^', '`', '_', '{', '|', '}', '~', - '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', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '?' - }; - - /** - * Translates the specified Base64 string (as per Preferences.get(byte[])) - * into a byte array. - * - * @throw IllegalArgumentException if s is not a valid Base64 - * string. - */ - static byte[] base64ToByteArray(String s) { - return base64ToByteArray(s, false); - } - - /** - * Translates the specified "aternate representation" Base64 string - * into a byte array. - * - * @throw IllegalArgumentException or ArrayOutOfBoundsException - * if s is not a valid alternate representation - * Base64 string. - */ - static byte[] altBase64ToByteArray(String s) { - return base64ToByteArray(s, true); - } - - private static byte[] base64ToByteArray(String s, boolean alternate) { - byte[] alphaToInt = (alternate ? altBase64ToInt : base64ToInt); - int sLen = s.length(); - int numGroups = sLen/4; - if (4*numGroups != sLen) - throw new IllegalArgumentException( - "String length must be a multiple of four."); - int missingBytesInLastGroup = 0; - int numFullGroups = numGroups; - if (sLen != 0) { - if (s.charAt(sLen-1) == '=') { - missingBytesInLastGroup++; - numFullGroups--; - } - if (s.charAt(sLen-2) == '=') - missingBytesInLastGroup++; - } - byte[] result = new byte[3*numGroups - missingBytesInLastGroup]; - - // Translate all full groups from base64 to byte array elements - int inCursor = 0, outCursor = 0; - for (int i=0; i> 4)); - result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); - result[outCursor++] = (byte) ((ch2 << 6) | ch3); - } - - // Translate partial group, if present - if (missingBytesInLastGroup != 0) { - int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt); - int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt); - result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); - - if (missingBytesInLastGroup == 1) { - int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt); - result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); - } - } - // assert inCursor == s.length()-missingBytesInLastGroup; - // assert outCursor == result.length; - return result; - } - - /** - * Translates the specified character, which is assumed to be in the - * "Base 64 Alphabet" into its equivalent 6-bit positive integer. - * - * @throw IllegalArgumentException or ArrayOutOfBoundsException if - * c is not in the Base64 Alphabet. - */ - private static int base64toInt(char c, byte[] alphaToInt) { - int result = alphaToInt[c]; - if (result < 0) - throw new IllegalArgumentException("Illegal character " + c); - return result; - } - - /** - * This array is a lookup table that translates unicode characters - * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045) - * into their 6-bit positive integer equivalents. Characters that - * are not in the Base64 alphabet but fall within the bounds of the - * array are translated to -1. - */ - private static final byte base64ToInt[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - }; - - /** - * This array is the analogue of base64ToInt, but for the nonstandard - * variant that avoids the use of uppercase alphabetic characters. - */ - private static final byte altBase64ToInt[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, - 2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 22, 23, 24, 25 - }; - -} diff --git a/jdk/src/share/classes/java/awt/Button.java b/jdk/src/share/classes/java/awt/Button.java index f0bad87430b..9fe42d41cbc 100644 --- a/jdk/src/share/classes/java/awt/Button.java +++ b/jdk/src/share/classes/java/awt/Button.java @@ -300,7 +300,7 @@ public class Button extends Component implements Accessible { * @since 1.4 */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[]) (getListeners(ActionListener.class)); + return getListeners(ActionListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/Checkbox.java b/jdk/src/share/classes/java/awt/Checkbox.java index 5c8e65f8aac..f0486f35e45 100644 --- a/jdk/src/share/classes/java/awt/Checkbox.java +++ b/jdk/src/share/classes/java/awt/Checkbox.java @@ -470,7 +470,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @since 1.4 */ public synchronized ItemListener[] getItemListeners() { - return (ItemListener[]) (getListeners(ItemListener.class)); + return getListeners(ItemListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/Choice.java b/jdk/src/share/classes/java/awt/Choice.java index 895be89a615..9ef765818dc 100644 --- a/jdk/src/share/classes/java/awt/Choice.java +++ b/jdk/src/share/classes/java/awt/Choice.java @@ -85,7 +85,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * @see #insert(String, int) * @see #remove(String) */ - Vector pItems; + Vector pItems; /** * The index of the current choice for this Choice @@ -129,7 +129,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { */ public Choice() throws HeadlessException { GraphicsEnvironment.checkHeadless(); - pItems = new Vector(); + pItems = new Vector<>(); } /** @@ -191,7 +191,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * be called on the toolkit thread. */ final String getItemImpl(int index) { - return (String)pItems.elementAt(index); + return pItems.elementAt(index); } /** @@ -524,7 +524,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * @since 1.4 */ public synchronized ItemListener[] getItemListeners() { - return (ItemListener[])(getListeners(ItemListener.class)); + return getListeners(ItemListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index e4f25f0da2b..42e422d3e93 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -7287,6 +7287,7 @@ public abstract class Component implements ImageObserver, MenuContainer, } final Set getFocusTraversalKeys_NoIDCheck(int id) { // Okay to return Set directly because it is an unmodifiable view + @SuppressWarnings("unchecked") Set keystrokes = (focusTraversalKeys != null) ? focusTraversalKeys[id] : null; diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index ce2a19138b1..78af6b10c62 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -161,7 +161,7 @@ public class Container extends Component { private boolean focusTraversalPolicyProvider; // keeps track of the threads that are printing this component - private transient Set printingThreads; + private transient Set printingThreads; // True if there is at least one thread that's printing this component private transient boolean printing = false; @@ -275,7 +275,7 @@ public class Container extends Component { */ public Container() { } - + @SuppressWarnings({"unchecked","rawtypes"}) void initializeFocusTraversalKeys() { focusTraversalKeys = new Set[4]; } @@ -2006,7 +2006,7 @@ public class Container extends Component { try { synchronized (getObjectLock()) { if (printingThreads == null) { - printingThreads = new HashSet(); + printingThreads = new HashSet<>(); } printingThreads.add(t); printing = true; @@ -2148,7 +2148,7 @@ public class Container extends Component { * @since 1.4 */ public synchronized ContainerListener[] getContainerListeners() { - return (ContainerListener[]) (getListeners(ContainerListener.class)); + return getListeners(ContainerListener.class); } /** @@ -2599,9 +2599,9 @@ public class Container extends Component { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } - PointerInfo pi = (PointerInfo)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { + PointerInfo pi = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public PointerInfo run() { return MouseInfo.getPointerInfo(); } } @@ -2682,7 +2682,7 @@ public class Container extends Component { y - comp.y, ignoreEnabled); } else { - comp = comp.locate(x - comp.x, y - comp.y); + comp = comp.getComponentAt(x - comp.x, y - comp.y); } if (comp != null && comp.visible && (ignoreEnabled || comp.enabled)) @@ -2700,7 +2700,7 @@ public class Container extends Component { y - comp.y, ignoreEnabled); } else { - comp = comp.locate(x - comp.x, y - comp.y); + comp = comp.getComponentAt(x - comp.x, y - comp.y); } if (comp != null && comp.visible && (ignoreEnabled || comp.enabled)) @@ -4637,7 +4637,7 @@ class LightweightDispatcher implements java.io.Serializable, AWTEventListener { private void startListeningForOtherDrags() { //System.out.println("Adding AWTEventListener"); java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction() { public Object run() { nativeContainer.getToolkit().addAWTEventListener( LightweightDispatcher.this, @@ -4652,7 +4652,7 @@ class LightweightDispatcher implements java.io.Serializable, AWTEventListener { private void stopListeningForOtherDrags() { //System.out.println("Removing AWTEventListener"); java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction() { public Object run() { nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this); return null; diff --git a/jdk/src/share/classes/java/awt/Dialog.java b/jdk/src/share/classes/java/awt/Dialog.java index 800d19c0200..622a4531d3a 100644 --- a/jdk/src/share/classes/java/awt/Dialog.java +++ b/jdk/src/share/classes/java/awt/Dialog.java @@ -1047,9 +1047,9 @@ public class Dialog extends Window { // if this dialog is toolkit-modal, the filter should be added // to all EDTs (for all AppContexts) if (modalityType == ModalityType.TOOLKIT_MODAL) { - Iterator it = AppContext.getAppContexts().iterator(); + Iterator it = AppContext.getAppContexts().iterator(); while (it.hasNext()) { - AppContext appContext = (AppContext)it.next(); + AppContext appContext = it.next(); if (appContext == showAppContext) { continue; } @@ -1084,9 +1084,9 @@ public class Dialog extends Window { // if this dialog is toolkit-modal, its filter must be removed // from all EDTs (for all AppContexts) if (modalityType == ModalityType.TOOLKIT_MODAL) { - Iterator it = AppContext.getAppContexts().iterator(); + Iterator it = AppContext.getAppContexts().iterator(); while (it.hasNext()) { - AppContext appContext = (AppContext)it.next(); + AppContext appContext = it.next(); if (appContext == showAppContext) { continue; } @@ -1396,7 +1396,7 @@ public class Dialog extends Window { if (d.shouldBlock(this)) { Window w = d; while ((w != null) && (w != this)) { - w = (Window)(w.getOwner_NoClientCode()); + w = w.getOwner_NoClientCode(); } if ((w == this) || !shouldBlock(d) || (modalityType.compareTo(d.getModalityType()) < 0)) { blockers.add(d); @@ -1611,7 +1611,7 @@ public class Dialog extends Window { setModal(modal); } - blockedWindows = new IdentityArrayList(); + blockedWindows = new IdentityArrayList<>(); } /* diff --git a/jdk/src/share/classes/java/awt/Frame.java b/jdk/src/share/classes/java/awt/Frame.java index 1a3173730e5..2513ddb75ef 100644 --- a/jdk/src/share/classes/java/awt/Frame.java +++ b/jdk/src/share/classes/java/awt/Frame.java @@ -353,7 +353,7 @@ public class Frame extends Window implements MenuContainer { * @serial * @see java.awt.Window#ownedWindowList */ - Vector ownedWindows; + Vector ownedWindows; private static final String base = "frame"; private static int nameCounter = 0; @@ -1242,7 +1242,7 @@ public class Frame extends Window implements MenuContainer { // if (ownedWindows != null) { for (int i = 0; i < ownedWindows.size(); i++) { - connectOwnedWindow((Window) ownedWindows.elementAt(i)); + connectOwnedWindow(ownedWindows.elementAt(i)); } ownedWindows = null; } diff --git a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java index 36a5b9b7fae..af9dcb1b2c2 100644 --- a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java +++ b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java @@ -416,7 +416,7 @@ public abstract class KeyboardFocusManager } } - static Set initFocusTraversalKeysSet(String value, Set targetSet) { + static Set initFocusTraversalKeysSet(String value, Set targetSet) { StringTokenizer tokens = new StringTokenizer(value, ","); while (tokens.hasMoreTokens()) { targetSet.add(AWTKeyStroke.getAWTKeyStroke(tokens.nextToken())); diff --git a/jdk/src/share/classes/java/awt/Scrollbar.java b/jdk/src/share/classes/java/awt/Scrollbar.java index fb033305e51..b6a581d96a8 100644 --- a/jdk/src/share/classes/java/awt/Scrollbar.java +++ b/jdk/src/share/classes/java/awt/Scrollbar.java @@ -1012,7 +1012,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * @since 1.4 */ public synchronized AdjustmentListener[] getAdjustmentListeners() { - return (AdjustmentListener[])(getListeners(AdjustmentListener.class)); + return getListeners(AdjustmentListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/TextArea.java b/jdk/src/share/classes/java/awt/TextArea.java index af76af8cbfa..8b16d9ec61d 100644 --- a/jdk/src/share/classes/java/awt/TextArea.java +++ b/jdk/src/share/classes/java/awt/TextArea.java @@ -123,7 +123,7 @@ public class TextArea extends TextComponent { * Cache the Sets of forward and backward traversal keys so we need not * look them up each time. */ - private static Set forwardTraversalKeys, backwardTraversalKeys; + private static Set forwardTraversalKeys, backwardTraversalKeys; /* * JDK 1.1 serialVersionUID @@ -143,10 +143,10 @@ public class TextArea extends TextComponent { } forwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet( "ctrl TAB", - new HashSet()); + new HashSet()); backwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet( "ctrl shift TAB", - new HashSet()); + new HashSet()); } /** diff --git a/jdk/src/share/classes/java/awt/TextComponent.java b/jdk/src/share/classes/java/awt/TextComponent.java index c99cae403a4..ecc9b3fd47c 100644 --- a/jdk/src/share/classes/java/awt/TextComponent.java +++ b/jdk/src/share/classes/java/awt/TextComponent.java @@ -606,7 +606,7 @@ public class TextComponent extends Component implements Accessible { * @since 1.4 */ public synchronized TextListener[] getTextListeners() { - return (TextListener[])(getListeners(TextListener.class)); + return getListeners(TextListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/TextField.java b/jdk/src/share/classes/java/awt/TextField.java index 268661c15f3..7c0e528f5f7 100644 --- a/jdk/src/share/classes/java/awt/TextField.java +++ b/jdk/src/share/classes/java/awt/TextField.java @@ -507,7 +507,7 @@ public class TextField extends TextComponent { * @since 1.4 */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[])(getListeners(ActionListener.class)); + return getListeners(ActionListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/Toolkit.java b/jdk/src/share/classes/java/awt/Toolkit.java index 8509534734c..783706a72b4 100644 --- a/jdk/src/share/classes/java/awt/Toolkit.java +++ b/jdk/src/share/classes/java/awt/Toolkit.java @@ -863,7 +863,7 @@ public abstract class Toolkit { new java.security.PrivilegedAction() { public Void run() { String nm = null; - Class cls = null; + Class cls = null; try { nm = System.getProperty("awt.toolkit"); try { diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 984e287bd50..4b9765443eb 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -441,7 +441,7 @@ public class Window extends Container implements Accessible { transient Object anchor = new Object(); static class WindowDisposerRecord implements sun.java2d.DisposerRecord { final WeakReference owner; - final WeakReference weakThis; + final WeakReference weakThis; final WeakReference context; WindowDisposerRecord(AppContext context, Window victim) { owner = new WeakReference(victim.getOwner()); @@ -1542,6 +1542,7 @@ public class Window extends Container implements Accessible { private static Window[] getWindows(AppContext appContext) { synchronized (Window.class) { Window realCopy[]; + @SuppressWarnings("unchecked") Vector> windowList = (Vector>)appContext.get(Window.class); if (windowList != null) { @@ -1866,7 +1867,7 @@ public class Window extends Container implements Accessible { * @since 1.4 */ public synchronized WindowListener[] getWindowListeners() { - return (WindowListener[])(getListeners(WindowListener.class)); + return getListeners(WindowListener.class); } /** @@ -1882,7 +1883,7 @@ public class Window extends Container implements Accessible { * @since 1.4 */ public synchronized WindowFocusListener[] getWindowFocusListeners() { - return (WindowFocusListener[])(getListeners(WindowFocusListener.class)); + return getListeners(WindowFocusListener.class); } /** @@ -1898,7 +1899,7 @@ public class Window extends Container implements Accessible { * @since 1.4 */ public synchronized WindowStateListener[] getWindowStateListeners() { - return (WindowStateListener[])(getListeners(WindowStateListener.class)); + return getListeners(WindowStateListener.class); } @@ -2014,7 +2015,6 @@ public class Window extends Container implements Accessible { break; case WindowEvent.WINDOW_STATE_CHANGED: processWindowStateEvent((WindowEvent)e); - default: break; } return; @@ -2382,12 +2382,14 @@ public class Window extends Container implements Accessible { * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS * @since 1.4 */ + @SuppressWarnings("unchecked") public Set getFocusTraversalKeys(int id) { if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } // Okay to return Set directly because it is an unmodifiable view + @SuppressWarnings("rawtypes") Set keystrokes = (focusTraversalKeys != null) ? focusTraversalKeys[id] : null; @@ -2765,7 +2767,7 @@ public class Window extends Container implements Accessible { /* * Support for tracking all windows owned by this window */ - void addOwnedWindow(WeakReference weakWindow) { + void addOwnedWindow(WeakReference weakWindow) { if (weakWindow != null) { synchronized(ownedWindowList) { // this if statement should really be an assert, but we don't @@ -2777,7 +2779,7 @@ public class Window extends Container implements Accessible { } } - void removeOwnedWindow(WeakReference weakWindow) { + void removeOwnedWindow(WeakReference weakWindow) { if (weakWindow != null) { // synchronized block not required since removeElement is // already synchronized @@ -2792,6 +2794,7 @@ public class Window extends Container implements Accessible { private void addToWindowList() { synchronized (Window.class) { + @SuppressWarnings("unchecked") Vector> windowList = (Vector>)appContext.get(Window.class); if (windowList == null) { windowList = new Vector>(); @@ -2801,8 +2804,9 @@ public class Window extends Container implements Accessible { } } - private static void removeFromWindowList(AppContext context, WeakReference weakThis) { + private static void removeFromWindowList(AppContext context, WeakReference weakThis) { synchronized (Window.class) { + @SuppressWarnings("unchecked") Vector> windowList = (Vector>)context.get(Window.class); if (windowList != null) { windowList.remove(weakThis); @@ -2945,7 +2949,7 @@ public class Window extends Container implements Accessible { // Deserialized Windows are not yet visible. visible = false; - weakThis = new WeakReference(this); + weakThis = new WeakReference<>(this); anchor = new Object(); sun.java2d.Disposer.addRecord(anchor, new WindowDisposerRecord(appContext, this)); @@ -2956,7 +2960,7 @@ public class Window extends Container implements Accessible { private void deserializeResources(ObjectInputStream s) throws ClassNotFoundException, IOException, HeadlessException { - ownedWindowList = new Vector(); + ownedWindowList = new Vector<>(); if (windowSerializedDataVersion < 2) { // Translate old-style focus tracking to new model. For 1.4 and diff --git a/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java b/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java index 81a43411563..eee5c0917d1 100644 --- a/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java +++ b/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -56,11 +56,6 @@ import sun.awt.datatransfer.DataTransferer; * by the data transfer subsystem to transfer data between Java and native * applications, and between Java applications in separate VMs. *

- * In the Sun reference implementation, the default SystemFlavorMap is - * initialized by the file jre/lib/flavormap.properties and the - * contents of the URL referenced by the AWT property - * AWT.DnD.flavorMapFileURL. See flavormap.properties - * for details. * * @since 1.2 */ @@ -1213,7 +1208,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { * are equal according to String.equals(Object). * *

- * Sun's reference implementation of this method returns the specified MIME + * The reference implementation of this method returns the specified MIME * type String prefixed with JAVA_DATAFLAVOR:. * * @param mimeType the MIME type to encode @@ -1241,7 +1236,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { * according to String.equals(Object). * *

- * Sun's reference implementation of this method returns the MIME type + * The reference implementation of this method returns the MIME type * String of the specified DataFlavor prefixed * with JAVA_DATAFLAVOR:. * diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java index 03999c445a5..6e4881cb832 100644 --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java @@ -35,6 +35,10 @@ import java.util.Arrays; * particular sequence of characters, but the length and content of the * sequence can be changed through certain method calls. * + *

Unless otherwise noted, passing a {@code null} argument to a constructor + * or method in this class will cause a {@link NullPointerException} to be + * thrown. + * * @author Michael McCloskey * @author Martin Buchholz * @author Ulf Zibis @@ -334,8 +338,6 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @param srcEnd stop copying at this offset. * @param dst the array to copy the data into. * @param dstBegin offset into {@code dst}. - * @throws NullPointerException if {@code dst} is - * {@code null}. * @throws IndexOutOfBoundsException if any of the following is true: *

    *
  • {@code srcBegin} is negative @@ -1282,8 +1284,6 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * object, then the index of the first character of the first * such substring is returned; if it does not occur as a * substring, {@code -1} is returned. - * @throws java.lang.NullPointerException if {@code str} is - * {@code null}. */ public int indexOf(String str) { return indexOf(str, 0); @@ -1303,8 +1303,6 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @param fromIndex the index from which to start the search. * @return the index within this string of the first occurrence of the * specified substring, starting at the specified index. - * @throws java.lang.NullPointerException if {@code str} is - * {@code null}. */ public int indexOf(String str, int fromIndex) { return String.indexOf(value, 0, count, str, fromIndex); @@ -1325,8 +1323,6 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * within this object, then the index of the first character of * the last such substring is returned. If it does not occur as * a substring, {@code -1} is returned. - * @throws java.lang.NullPointerException if {@code str} is - * {@code null}. */ public int lastIndexOf(String str) { return lastIndexOf(str, count); @@ -1346,8 +1342,6 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @param fromIndex the index to start the search from. * @return the index within this sequence of the last occurrence of the * specified substring. - * @throws java.lang.NullPointerException if {@code str} is - * {@code null}. */ public int lastIndexOf(String str, int fromIndex) { return String.lastIndexOf(value, 0, count, str, fromIndex); diff --git a/jdk/src/share/classes/java/lang/Boolean.java b/jdk/src/share/classes/java/lang/Boolean.java index 2c4754c8a61..fbbeba72ce0 100644 --- a/jdk/src/share/classes/java/lang/Boolean.java +++ b/jdk/src/share/classes/java/lang/Boolean.java @@ -290,4 +290,46 @@ public final class Boolean implements java.io.Serializable, public static int compare(boolean x, boolean y) { return (x == y) ? 0 : (x ? 1 : -1); } + + /** + * Returns the result of applying the logical AND operator to the + * specified {@code boolean} operands. + * + * @param a the first operand + * @param b the second operand + * @return the logical AND of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static boolean logicalAnd(boolean a, boolean b) { + return a && b; + } + + /** + * Returns the result of applying the logical OR operator to the + * specified {@code boolean} operands. + * + * @param a the first operand + * @param b the second operand + * @return the logical OR of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static boolean logicalOr(boolean a, boolean b) { + return a || b; + } + + /** + * Returns the result of applying the logical XOR operator to the + * specified {@code boolean} operands. + * + * @param a the first operand + * @param b the second operand + * @return the logical XOR of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static boolean logicalXor(boolean a, boolean b) { + return a ^ b; + } } diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index e1ac4029985..094f0cf26d6 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.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 @@ -2214,39 +2214,89 @@ public final // Caches for certain reflective results private static boolean useCaches = true; - private volatile transient SoftReference declaredFields; - private volatile transient SoftReference publicFields; - private volatile transient SoftReference declaredMethods; - private volatile transient SoftReference publicMethods; - private volatile transient SoftReference[]> declaredConstructors; - private volatile transient SoftReference[]> publicConstructors; - // Intermediate results for getFields and getMethods - private volatile transient SoftReference declaredPublicFields; - private volatile transient SoftReference declaredPublicMethods; + + // reflection data that might get invalidated when JVM TI RedefineClasses() is called + static class ReflectionData { + volatile Field[] declaredFields; + volatile Field[] publicFields; + volatile Method[] declaredMethods; + volatile Method[] publicMethods; + volatile Constructor[] declaredConstructors; + volatile Constructor[] publicConstructors; + // Intermediate results for getFields and getMethods + volatile Field[] declaredPublicFields; + volatile Method[] declaredPublicMethods; + // Value of classRedefinedCount when we created this ReflectionData instance + final int redefinedCount; + + ReflectionData(int redefinedCount) { + this.redefinedCount = redefinedCount; + } + + // initialize Unsafe machinery here, since we need to call Class.class instance method + // and have to avoid calling it in the static initializer of the Class class... + private static final Unsafe unsafe; + // offset of Class.reflectionData instance field + private static final long reflectionDataOffset; + + static { + unsafe = Unsafe.getUnsafe(); + // bypass caches + Field reflectionDataField = searchFields(Class.class.getDeclaredFields0(false), + "reflectionData"); + if (reflectionDataField == null) { + throw new Error("No reflectionData field found in java.lang.Class"); + } + reflectionDataOffset = unsafe.objectFieldOffset(reflectionDataField); + } + + static boolean compareAndSwap(Class clazz, + SoftReference> oldData, + SoftReference> newData) { + return unsafe.compareAndSwapObject(clazz, reflectionDataOffset, oldData, newData); + } + } + + private volatile transient SoftReference> reflectionData; // Incremented by the VM on each call to JVM TI RedefineClasses() // that redefines this class or a superclass. private volatile transient int classRedefinedCount = 0; - // Value of classRedefinedCount when we last cleared the cached values - // that are sensitive to class redefinition. - private volatile transient int lastRedefinedCount = 0; + // Lazily create and cache ReflectionData + private ReflectionData reflectionData() { + SoftReference> reflectionData = this.reflectionData; + int classRedefinedCount = this.classRedefinedCount; + ReflectionData rd; + if (useCaches && + reflectionData != null && + (rd = reflectionData.get()) != null && + rd.redefinedCount == classRedefinedCount) { + return rd; + } + // else no SoftReference or cleared SoftReference or stale ReflectionData + // -> create and replace new instance + return newReflectionData(reflectionData, classRedefinedCount); + } - // Clears cached values that might possibly have been obsoleted by - // a class redefinition. - private void clearCachesOnClassRedefinition() { - if (lastRedefinedCount != classRedefinedCount) { - declaredFields = publicFields = declaredPublicFields = null; - declaredMethods = publicMethods = declaredPublicMethods = null; - declaredConstructors = publicConstructors = null; - annotations = declaredAnnotations = null; + private ReflectionData newReflectionData(SoftReference> oldReflectionData, + int classRedefinedCount) { + if (!useCaches) return null; - // Use of "volatile" (and synchronization by caller in the case - // of annotations) ensures that no thread sees the update to - // lastRedefinedCount before seeing the caches cleared. - // We do not guard against brief windows during which multiple - // threads might redundantly work to fill an empty cache. - lastRedefinedCount = classRedefinedCount; + while (true) { + ReflectionData rd = new ReflectionData<>(classRedefinedCount); + // try to CAS it... + if (ReflectionData.compareAndSwap(this, oldReflectionData, new SoftReference<>(rd))) { + return rd; + } + // else retry + oldReflectionData = this.reflectionData; + classRedefinedCount = this.classRedefinedCount; + if (oldReflectionData != null && + (rd = oldReflectionData.get()) != null && + rd.redefinedCount == classRedefinedCount) { + return rd; + } } } @@ -2289,27 +2339,19 @@ public final // via ReflectionFactory.copyField. private Field[] privateGetDeclaredFields(boolean publicOnly) { checkInitted(); - Field[] res = null; - if (useCaches) { - clearCachesOnClassRedefinition(); - if (publicOnly) { - if (declaredPublicFields != null) { - res = declaredPublicFields.get(); - } - } else { - if (declaredFields != null) { - res = declaredFields.get(); - } - } + Field[] res; + ReflectionData rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.declaredPublicFields : rd.declaredFields; if (res != null) return res; } // No cached value available; request value from VM res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); - if (useCaches) { + if (rd != null) { if (publicOnly) { - declaredPublicFields = new SoftReference<>(res); + rd.declaredPublicFields = res; } else { - declaredFields = new SoftReference<>(res); + rd.declaredFields = res; } } return res; @@ -2320,12 +2362,10 @@ public final // via ReflectionFactory.copyField. private Field[] privateGetPublicFields(Set> traversedInterfaces) { checkInitted(); - Field[] res = null; - if (useCaches) { - clearCachesOnClassRedefinition(); - if (publicFields != null) { - res = publicFields.get(); - } + Field[] res; + ReflectionData rd = reflectionData(); + if (rd != null) { + res = rd.publicFields; if (res != null) return res; } @@ -2358,8 +2398,8 @@ public final res = new Field[fields.size()]; fields.toArray(res); - if (useCaches) { - publicFields = new SoftReference<>(res); + if (rd != null) { + rd.publicFields = res; } return res; } @@ -2382,18 +2422,10 @@ public final // instead be copied via ReflectionFactory.copyConstructor. private Constructor[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); - Constructor[] res = null; - if (useCaches) { - clearCachesOnClassRedefinition(); - if (publicOnly) { - if (publicConstructors != null) { - res = publicConstructors.get(); - } - } else { - if (declaredConstructors != null) { - res = declaredConstructors.get(); - } - } + Constructor[] res; + ReflectionData rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; if (res != null) return res; } // No cached value available; request value from VM @@ -2404,11 +2436,11 @@ public final } else { res = getDeclaredConstructors0(publicOnly); } - if (useCaches) { + if (rd != null) { if (publicOnly) { - publicConstructors = new SoftReference<>(res); + rd.publicConstructors = res; } else { - declaredConstructors = new SoftReference<>(res); + rd.declaredConstructors = res; } } return res; @@ -2425,27 +2457,19 @@ public final // via ReflectionFactory.copyMethod. private Method[] privateGetDeclaredMethods(boolean publicOnly) { checkInitted(); - Method[] res = null; - if (useCaches) { - clearCachesOnClassRedefinition(); - if (publicOnly) { - if (declaredPublicMethods != null) { - res = declaredPublicMethods.get(); - } - } else { - if (declaredMethods != null) { - res = declaredMethods.get(); - } - } + Method[] res; + ReflectionData rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; if (res != null) return res; } // No cached value available; request value from VM res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); - if (useCaches) { + if (rd != null) { if (publicOnly) { - declaredPublicMethods = new SoftReference<>(res); + rd.declaredPublicMethods = res; } else { - declaredMethods = new SoftReference<>(res); + rd.declaredMethods = res; } } return res; @@ -2547,12 +2571,10 @@ public final // via ReflectionFactory.copyMethod. private Method[] privateGetPublicMethods() { checkInitted(); - Method[] res = null; - if (useCaches) { - clearCachesOnClassRedefinition(); - if (publicMethods != null) { - res = publicMethods.get(); - } + Method[] res; + ReflectionData rd = reflectionData(); + if (rd != null) { + res = rd.publicMethods; if (res != null) return res; } @@ -2560,7 +2582,7 @@ public final // Start by fetching public declared methods MethodArray methods = new MethodArray(); { - Method[] tmp = privateGetDeclaredMethods(true); + Method[] tmp = privateGetDeclaredMethods(true); methods.addAll(tmp); } // Now recur over superclass and direct superinterfaces. @@ -2600,8 +2622,8 @@ public final methods.addAllIfNotPresent(inheritedMethods); methods.compactAndTrim(); res = methods.getArray(); - if (useCaches) { - publicMethods = new SoftReference<>(res); + if (rd != null) { + rd.publicMethods = res; } return res; } @@ -2611,7 +2633,7 @@ public final // Helpers for fetchers of one field, method, or constructor // - private Field searchFields(Field[] fields, String name) { + private static Field searchFields(Field[] fields, String name) { String internedName = name.intern(); for (int i = 0; i < fields.length; i++) { if (fields[i].getName() == internedName) { @@ -2629,7 +2651,7 @@ public final // of Field objects which have to be created for the common // case where the field being requested is declared in the // class which is being queried. - Field res = null; + Field res; // Search declared public fields if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) { return res; @@ -2681,7 +2703,7 @@ public final // number of Method objects which have to be created for the // common case where the method being requested is declared in // the class which is being queried. - Method res = null; + Method res; // Search declared public methods if ((res = searchMethods(privateGetDeclaredMethods(true), name, @@ -3125,9 +3147,20 @@ public final // Annotations cache private transient Map, Annotation> annotations; private transient Map, Annotation> declaredAnnotations; + // Value of classRedefinedCount when we last cleared the cached annotations and declaredAnnotations fields + private transient int lastAnnotationsRedefinedCount = 0; + + // Clears cached values that might possibly have been obsoleted by + // a class redefinition. + private void clearAnnotationCachesOnClassRedefinition() { + if (lastAnnotationsRedefinedCount != classRedefinedCount) { + annotations = declaredAnnotations = null; + lastAnnotationsRedefinedCount = classRedefinedCount; + } + } private synchronized void initAnnotationsIfNecessary() { - clearCachesOnClassRedefinition(); + clearAnnotationCachesOnClassRedefinition(); if (annotations != null) return; declaredAnnotations = AnnotationParser.parseAnnotations( diff --git a/jdk/src/share/classes/java/lang/Double.java b/jdk/src/share/classes/java/lang/Double.java index a20f79e6cb3..f79980f4bb8 100644 --- a/jdk/src/share/classes/java/lang/Double.java +++ b/jdk/src/share/classes/java/lang/Double.java @@ -1021,6 +1021,48 @@ public final class Double extends Number implements Comparable { 1)); // (0.0, -0.0) or (NaN, !NaN) } + /** + * Adds two {@code double} values together as per the + operator. + * + * @param a the first operand + * @param b the second operand + * @return the sum of {@code a} and {@code b} + * @jls 4.2.4 Floating-Point Operations + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static double sum(double a, double b) { + return a + b; + } + + /** + * Returns the greater of two {@code double} values + * as if by calling {@link Math#max(double, double) Math.max}. + * + * @param a the first operand + * @param b the second operand + * @return the greater of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static double max(double a, double b) { + return Math.max(a, b); + } + + /** + * Returns the smaller of two {@code double} values + * as if by calling {@link Math#min(double, double) Math.min}. + * + * @param a the first operand + * @param b the second operand + * @return the smaller of {@code a} and {@code b}. + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static double min(double a, double b) { + return Math.min(a, b); + } + /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -9172774392245257468L; } diff --git a/jdk/src/share/classes/java/lang/Float.java b/jdk/src/share/classes/java/lang/Float.java index 0c071e2b0f4..bdb8f63fbf1 100644 --- a/jdk/src/share/classes/java/lang/Float.java +++ b/jdk/src/share/classes/java/lang/Float.java @@ -926,6 +926,48 @@ public final class Float extends Number implements Comparable { 1)); // (0.0, -0.0) or (NaN, !NaN) } + /** + * Adds two {@code float} values together as per the + operator. + * + * @param a the first operand + * @param b the second operand + * @return the sum of {@code a} and {@code b} + * @jls 4.2.4 Floating-Point Operations + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static float sum(float a, float b) { + return a + b; + } + + /** + * Returns the greater of two {@code float} values + * as if by calling {@link Math#max(float, float) Math.max}. + * + * @param a the first operand + * @param b the second operand + * @return the greater of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static float max(float a, float b) { + return Math.max(a, b); + } + + /** + * Returns the smaller of two {@code float} values + * as if by calling {@link Math#min(float, float) Math.min}. + * + * @param a the first operand + * @param b the second operand + * @return the smaller of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static float min(float a, float b) { + return Math.min(a, b); + } + /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -2671257302660747028L; } diff --git a/jdk/src/share/classes/java/lang/FunctionalInterface.java b/jdk/src/share/classes/java/lang/FunctionalInterface.java index 0d4ae72a697..a93ed51f91c 100644 --- a/jdk/src/share/classes/java/lang/FunctionalInterface.java +++ b/jdk/src/share/classes/java/lang/FunctionalInterface.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 @@ -28,9 +28,9 @@ package java.lang; import java.lang.annotation.*; /** - * Indicates that an interface type declaration is intended to be a - * functional interface as defined by the Java Language - * Specification. + * An informative annotation type used to indicate that an interface + * type declaration is intended to be a functional interface as + * defined by the Java Language Specification. * * Conceptually, a functional interface has exactly one abstract * method. Since {@linkplain java.lang.reflect.Method#isDefault() @@ -52,6 +52,11 @@ import java.lang.annotation.*; *
  • The annotated type satisfies the requirements of a functional interface. *
* + *

However, the compiler will treat any interface meeting the + * definition of a functional interface as a functional interface + * regardless of whether or not a {@code FunctionalInterface} + * annotation is present on the interface declaration. + * * @jls 4.3.2. The Class Object * @jls 9.8 Functional Interfaces * @jls 9.4.3 Interface Method Body diff --git a/jdk/src/share/classes/java/lang/Integer.java b/jdk/src/share/classes/java/lang/Integer.java index b27f46358c5..a0eeecf2d98 100644 --- a/jdk/src/share/classes/java/lang/Integer.java +++ b/jdk/src/share/classes/java/lang/Integer.java @@ -1513,6 +1513,47 @@ public final class Integer extends Number implements Comparable { ((i << 24)); } + /** + * Adds two integers together as per the + operator. + * + * @param a the first operand + * @param b the second operand + * @return the sum of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static int sum(int a, int b) { + return a + b; + } + + /** + * Returns the greater of two {@code int} values + * as if by calling {@link Math#max(int, int) Math.max}. + * + * @param a the first operand + * @param b the second operand + * @return the greater of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static int max(int a, int b) { + return Math.max(a, b); + } + + /** + * Returns the smaller of two {@code int} values + * as if by calling {@link Math#min(int, int) Math.min}. + * + * @param a the first operand + * @param b the second operand + * @return the smaller of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static int min(int a, int b) { + return Math.min(a, b); + } + /** use serialVersionUID from JDK 1.0.2 for interoperability */ @Native private static final long serialVersionUID = 1360826667806852920L; } diff --git a/jdk/src/share/classes/java/lang/Long.java b/jdk/src/share/classes/java/lang/Long.java index 35cb2a4b64d..b67c8520547 100644 --- a/jdk/src/share/classes/java/lang/Long.java +++ b/jdk/src/share/classes/java/lang/Long.java @@ -1540,6 +1540,47 @@ public final class Long extends Number implements Comparable { ((i >>> 16) & 0xffff0000L) | (i >>> 48); } + /** + * Adds two {@code long} values together as per the + operator. + * + * @param a the first operand + * @param b the second operand + * @return the sum of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static long sum(long a, long b) { + return a + b; + } + + /** + * Returns the greater of two {@code long} values + * as if by calling {@link Math#max(long, long) Math.max}. + * + * @param a the first operand + * @param b the second operand + * @return the greater of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static long max(long a, long b) { + return Math.max(a, b); + } + + /** + * Returns the smaller of two {@code long} values + * as if by calling {@link Math#min(long, long) Math.min}. + * + * @param a the first operand + * @param b the second operand + * @return the smaller of {@code a} and {@code b} + * @see java.util.function.BinaryOperator + * @since 1.8 + */ + public static long min(long a, long b) { + return Math.min(a, b); + } + /** use serialVersionUID from JDK 1.0.2 for interoperability */ @Native private static final long serialVersionUID = 4290774380558885855L; } diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java index a9bc2f37648..7679a45a73a 100644 --- a/jdk/src/share/classes/java/lang/String.java +++ b/jdk/src/share/classes/java/lang/String.java @@ -33,6 +33,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.Formatter; import java.util.Locale; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -871,6 +872,8 @@ public final class String if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } + Objects.requireNonNull(dst); + int j = dstBegin; int n = srcEnd; int i = srcBegin; @@ -2112,7 +2115,6 @@ public final class String * * @param s the sequence to search for * @return true if this string contains {@code s}, false otherwise - * @throws NullPointerException if {@code s} is {@code null} * @since 1.5 */ public boolean contains(CharSequence s) { @@ -2219,8 +2221,6 @@ public final class String * @param target The sequence of char values to be replaced * @param replacement The replacement sequence of char values * @return The resulting string - * @throws NullPointerException if {@code target} or - * {@code replacement} is {@code null}. * @since 1.5 */ public String replace(CharSequence target, CharSequence replacement) { @@ -2833,9 +2833,6 @@ public final class String * href="../util/Formatter.html#detail">Details section of the * formatter class specification. * - * @throws NullPointerException - * If the {@code format} is {@code null} - * * @return A formatted string * * @see java.util.Formatter @@ -2865,8 +2862,8 @@ public final class String * limited by the maximum dimension of a Java array as defined by * The Java™ Virtual Machine Specification. * The behaviour on a - * {@code null} argument depends on the conversion. + * {@code null} argument depends on the + * conversion. * * @throws java.util.IllegalFormatException * If a format string contains an illegal syntax, a format @@ -2877,9 +2874,6 @@ public final class String * href="../util/Formatter.html#detail">Details section of the * formatter class specification * - * @throws NullPointerException - * If the {@code format} is {@code null} - * * @return A formatted string * * @see java.util.Formatter diff --git a/jdk/src/share/classes/java/lang/StringBuffer.java b/jdk/src/share/classes/java/lang/StringBuffer.java index 5d7754a0cc7..f31a53c98e6 100644 --- a/jdk/src/share/classes/java/lang/StringBuffer.java +++ b/jdk/src/share/classes/java/lang/StringBuffer.java @@ -77,7 +77,11 @@ package java.lang; * the capacity, it is not necessary to allocate a new internal * buffer array. If the internal buffer overflows, it is * automatically made larger. - * + *

+ * Unless otherwise noted, passing a {@code null} argument to a constructor + * or method in this class will cause a {@link NullPointerException} to be + * thrown. + *

* As of release JDK 5, this class has been supplemented with an equivalent * class designed for use by a single thread, {@link StringBuilder}. The * {@code StringBuilder} class should generally be used in preference to @@ -123,7 +127,6 @@ package java.lang; * {@code 16} plus the length of the string argument. * * @param str the initial contents of the buffer. - * @exception NullPointerException if {@code str} is {@code null} */ public StringBuffer(String str) { super(str.length() + 16); @@ -141,7 +144,6 @@ package java.lang; * {@code 16} is returned. * * @param seq the sequence to copy. - * @exception NullPointerException if {@code seq} is {@code null} * @since 1.5 */ public StringBuffer(CharSequence seq) { @@ -228,7 +230,6 @@ package java.lang; } /** - * @throws NullPointerException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override @@ -584,7 +585,6 @@ package java.lang; } /** - * @throws NullPointerException {@inheritDoc} * @since 1.4 */ @Override @@ -594,7 +594,6 @@ package java.lang; } /** - * @throws NullPointerException {@inheritDoc} * @since 1.4 */ @Override @@ -603,7 +602,6 @@ package java.lang; } /** - * @throws NullPointerException {@inheritDoc} * @since 1.4 */ @Override @@ -613,7 +611,6 @@ package java.lang; } /** - * @throws NullPointerException {@inheritDoc} * @since 1.4 */ @Override diff --git a/jdk/src/share/classes/java/lang/StringBuilder.java b/jdk/src/share/classes/java/lang/StringBuilder.java index e9defe23f6f..bfa2d83d232 100644 --- a/jdk/src/share/classes/java/lang/StringBuilder.java +++ b/jdk/src/share/classes/java/lang/StringBuilder.java @@ -64,6 +64,10 @@ package java.lang; * use by multiple threads. If such synchronization is required then it is * recommended that {@link java.lang.StringBuffer} be used. * + *

Unless otherwise noted, passing a {@code null} argument to a constructor + * or method in this class will cause a {@link NullPointerException} to be + * thrown. + * * @author Michael McCloskey * @see java.lang.StringBuffer * @see java.lang.String @@ -103,7 +107,6 @@ public final class StringBuilder * {@code 16} plus the length of the string argument. * * @param str the initial contents of the buffer. - * @throws NullPointerException if {@code str} is {@code null} */ public StringBuilder(String str) { super(str.length() + 16); @@ -117,7 +120,6 @@ public final class StringBuilder * {@code CharSequence} argument. * * @param seq the sequence to copy. - * @throws NullPointerException if {@code seq} is {@code null} */ public StringBuilder(CharSequence seq) { this(seq.length() + 16); @@ -373,33 +375,21 @@ public final class StringBuilder return this; } - /** - * @throws NullPointerException {@inheritDoc} - */ @Override public int indexOf(String str) { return super.indexOf(str); } - /** - * @throws NullPointerException {@inheritDoc} - */ @Override public int indexOf(String str, int fromIndex) { return super.indexOf(str, fromIndex); } - /** - * @throws NullPointerException {@inheritDoc} - */ @Override public int lastIndexOf(String str) { return super.lastIndexOf(str); } - /** - * @throws NullPointerException {@inheritDoc} - */ @Override public int lastIndexOf(String str, int fromIndex) { return super.lastIndexOf(str, fromIndex); diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index 15588ff0f9d..64987bdc2fa 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -2028,6 +2028,16 @@ class Thread implements Runnable { } } + + // The following three initially uninitialized fields are exclusively + // managed by class java.util.concurrent.ThreadLocalRandom. + /** The current seed for a ThreadLocalRandom */ + long threadLocalRandomSeed; + /** Probe hash value; nonzero if threadLocalRandomSeed initialized */ + int threadLocalRandomProbe; + /** Secondary seed isolated from public ThreadLocalRandom sequence */ + int threadLocalRandomSecondarySeed; + /* Some private helper methods */ private native void setPriority0(int newPriority); private native void stop0(Object o); diff --git a/jdk/src/share/classes/java/lang/instrument/package.html b/jdk/src/share/classes/java/lang/instrument/package.html index 6e9febdef9b..eb73ee37654 100644 --- a/jdk/src/share/classes/java/lang/instrument/package.html +++ b/jdk/src/share/classes/java/lang/instrument/package.html @@ -53,8 +53,10 @@ dependent.

Command-Line Interface

-On implementations with a command-line interface, an agent is started by -adding this option to the command-line: +An implementation is not required to provide a way to start agents from the +command-line interface. On implementations that do provide a way to start agents +from the command-line interface, an agent is started by adding this option to +the command-line:

-javaagent:jarpath[=options]
diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java index 73e4d271e17..1973e820950 100644 --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -203,6 +203,11 @@ public final class Constructor extends Executable { return parameterTypes.clone(); } + /** + * {@inheritDoc} + */ + public int getParameterCount() { return parameterTypes.length; } + /** * {@inheritDoc} * @throws GenericSignatureFormatError {@inheritDoc} diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java index 724b4838fe7..f2befd2dcdd 100644 --- a/jdk/src/share/classes/java/lang/reflect/Executable.java +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java @@ -1,5 +1,5 @@ /* - * 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 @@ -225,6 +225,18 @@ public abstract class Executable extends AccessibleObject */ public abstract Class[] getParameterTypes(); + /** + * Returns the number of formal parameters (including any + * synthetic or synthesized parameters) for the executable + * represented by this object. + * + * @return The number of formal parameters for the executable this + * object represents + */ + public int getParameterCount() { + throw new AbstractMethodError(); + } + /** * Returns an array of {@code Type} objects that represent the formal * parameter types, in declaration order, of the executable represented by @@ -258,6 +270,60 @@ public abstract class Executable extends AccessibleObject return getParameterTypes(); } + /** + * Returns an array of {@code Parameter} objects that represent + * all the parameters to the underlying executable represented by + * this object. Returns an array of length 0 if the executable + * has no parameters. + * + * @return an array of {@code Parameter} objects representing all + * the parameters to the executable this object represents + */ + public Parameter[] getParameters() { + // TODO: This may eventually need to be guarded by security + // mechanisms similar to those in Field, Method, etc. + // + // Need to copy the cached array to prevent users from messing + // with it. Since parameters are immutable, we can + // shallow-copy. + return privateGetParameters().clone(); + } + + private Parameter[] synthesizeAllParams() { + final int realparams = getParameterCount(); + final Parameter[] out = new Parameter[realparams]; + for (int i = 0; i < realparams; i++) + // TODO: is there a way to synthetically derive the + // modifiers? Probably not in the general case, since + // we'd have no way of knowing about them, but there + // may be specific cases. + out[i] = new Parameter("arg" + i, 0, this, i); + return out; + } + + private Parameter[] privateGetParameters() { + // Use tmp to avoid multiple writes to a volatile. + Parameter[] tmp = parameters; + + if (tmp == null) { + + // Otherwise, go to the JVM to get them + tmp = getParameters0(); + + // If we get back nothing, then synthesize parameters + if (tmp == null) + tmp = synthesizeAllParams(); + + parameters = tmp; + } + + return tmp; + } + + private transient volatile Parameter[] parameters; + + private native Parameter[] getParameters0(); + /** * Returns an array of {@code Class} objects that represent the * types of exceptions declared to be thrown by the underlying @@ -403,4 +469,5 @@ public abstract class Executable extends AccessibleObject } return declaredAnnotations; } + } diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java index f67ca224447..a7beb011400 100644 --- a/jdk/src/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/share/classes/java/lang/reflect/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -253,6 +253,12 @@ public final class Method extends Executable { return parameterTypes.clone(); } + /** + * {@inheritDoc} + */ + public int getParameterCount() { return parameterTypes.length; } + + /** * {@inheritDoc} * @throws GenericSignatureFormatError {@inheritDoc} diff --git a/jdk/src/share/classes/java/lang/reflect/Modifier.java b/jdk/src/share/classes/java/lang/reflect/Modifier.java index 3d0eed2c2cc..24cebe29f9f 100644 --- a/jdk/src/share/classes/java/lang/reflect/Modifier.java +++ b/jdk/src/share/classes/java/lang/reflect/Modifier.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 @@ -340,12 +340,17 @@ class Modifier { static final int BRIDGE = 0x00000040; static final int VARARGS = 0x00000080; static final int SYNTHETIC = 0x00001000; - static final int ANNOTATION= 0x00002000; + static final int ANNOTATION = 0x00002000; static final int ENUM = 0x00004000; + static final int SYNTHESIZED = 0x00010000; static boolean isSynthetic(int mod) { return (mod & SYNTHETIC) != 0; } + static boolean isSynthesized(int mod) { + return (mod & SYNTHESIZED) != 0; + } + /** * See JLSv3 section 8.1.1. */ diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java new file mode 100644 index 00000000000..6eed6926be0 --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java @@ -0,0 +1,305 @@ +/* + * 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 java.lang.reflect; + +import java.lang.annotation.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import sun.reflect.annotation.AnnotationSupport; + +/** + * Information about method parameters. + * + * A {@code Parameter} provides information about method parameters, + * including its name and modifiers. It also provides an alternate + * means of obtaining attributes for the parameter. + * + * @since 1.8 + */ +public final class Parameter implements AnnotatedElement { + + private final String name; + private final int modifiers; + private final Executable executable; + private int index; + + /** + * Package-private constructor for {@code Parameter}. + * + * If method parameter data is present in the classfile, then the + * JVM creates {@code Parameter} objects directly. If it is + * absent, however, then {@code Executable} uses this constructor + * to synthesize them. + * + * @param name The name of the parameter. + * @param modifiers The modifier flags for the parameter. + * @param executable The executable which defines this parameter. + * @param index The index of the parameter. + */ + Parameter(String name, + int modifiers, + Executable executable, + int index) { + this.name = name; + this.modifiers = modifiers; + this.executable = executable; + this.index = index; + } + + /** + * Compares based on the executable and the index. + * + * @param obj The object to compare. + * @return Whether or not this is equal to the argument. + */ + public boolean equals(Object obj) { + if(obj instanceof Parameter) { + Parameter other = (Parameter)obj; + return (other.executable.equals(executable) && + other.index == index); + } + return false; + } + + /** + * Returns a hash code based on the executable's hash code and the + * index. + * + * @return A hash code based on the executable's hash code. + */ + public int hashCode() { + return executable.hashCode() ^ index; + } + + /** + * Returns a string representation of the parameter's modifiers, + * its attributes, its type, its name, and a trailing ... if it is + * a variadic parameter. + * + * @return A string representation of the parameter and associated + * information. + */ + public String toString() { + final StringBuilder sb = new StringBuilder(); + final Type type = getParameterizedType(); + final String typename = (type instanceof Class)? + Field.getTypeName((Class)type): + (type.toString()); + + sb.append(Modifier.toString(getModifiers())); + sb.append(" "); + + if(isVarArgs()) + sb.append(typename.replaceFirst("\\[\\]$", "...")); + else + sb.append(typename); + + sb.append(" "); + sb.append(name); + + return sb.toString(); + } + + /** + * Return the {@code Executable} which declares this parameter. + * + * @return The {@code Executable} declaring this parameter. + */ + public Executable getDeclaringExecutable() { + return executable; + } + + /** + * Get the modifier flags for this the parameter represented by + * this {@code Parameter} object. + * + * @return The modifier flags for this parameter. + */ + public int getModifiers() { + return modifiers; + } + + /** + * Returns the name of the parameter represented by this + * {@code Parameter} object. + */ + public String getName() { + return name; + } + + /** + * Returns a {@code Type} object that identifies the parameterized + * type for the parameter represented by this {@code Parameter} + * object. + * + * @return a {@code Type} object identifying the parameterized + * type of the parameter represented by this object + */ + public Type getParameterizedType() { + Type tmp = parameterTypeCache; + if (null == tmp) { + tmp = executable.getGenericParameterTypes()[index]; + parameterTypeCache = tmp; + } + + return tmp; + } + + private transient volatile Type parameterTypeCache = null; + + /** + * Returns a {@code Class} object that identifies the + * declared type for the parameter represented by this + * {@code Parameter} object. + * + * @return a {@code Class} object identifying the declared + * type of the parameter represented by this object + */ + public Class getType() { + Class tmp = parameterClassCache; + if (null == tmp) { + tmp = executable.getParameterTypes()[index]; + parameterClassCache = tmp; + } + return tmp; + } + + private transient volatile Class parameterClassCache = null; + + /** + * Returns {@code true} if this parameter is a synthesized + * construct; returns {@code false} otherwise. + * + * @return true if and only if this parameter is a synthesized + * construct as defined by + * The Java™ Language Specification. + */ + public boolean isSynthesized() { + return Modifier.isSynthesized(getModifiers()); + } + + /** + * Returns {@code true} if this parameter is a synthetic + * construct; returns {@code false} otherwise. + * + * @jls 13.1 The Form of a Binary + * @return true if and only if this parameter is a synthetic + * construct as defined by + * The Java™ Language Specification. + */ + public boolean isSynthetic() { + return Modifier.isSynthetic(getModifiers()); + } + + /** + * Returns {@code true} if this parameter represents a variable + * argument list; returns {@code false} otherwise. + * + * @return {@code true} if an only if this parameter represents a + * variable argument list. + */ + public boolean isVarArgs() { + return executable.isVarArgs() && + index == executable.getParameterCount() - 1; + } + + + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public T getAnnotation(Class annotationClass) { + Objects.requireNonNull(annotationClass); + + return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass); + } + + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public T[] getAnnotations(Class annotationClass) { + Objects.requireNonNull(annotationClass); + + return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); + } + + /** + * {@inheritDoc} + */ + public Annotation[] getDeclaredAnnotations() { + return executable.getParameterAnnotations()[index]; + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public T getDeclaredAnnotation(Class annotationClass) { + // Only annotations on classes are inherited, for all other + // objects getDeclaredAnnotation is the same as + // getAnnotation. + return getAnnotation(annotationClass); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public T[] getDeclaredAnnotations(Class annotationClass) { + // Only annotations on classes are inherited, for all other + // objects getDeclaredAnnotations is the same as + // getAnnotations. + return getAnnotations(annotationClass); + } + + /** + * {@inheritDoc} + */ + public Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean isAnnotationPresent( + Class annotationClass) { + return getAnnotation(annotationClass) != null; + } + + private transient Map, Annotation> declaredAnnotations; + + private synchronized Map, Annotation> declaredAnnotations() { + if(null == declaredAnnotations) { + declaredAnnotations = + new HashMap, Annotation>(); + Annotation[] ann = getDeclaredAnnotations(); + for(int i = 0; i < ann.length; i++) + declaredAnnotations.put(ann[i].annotationType(), ann[i]); + } + return declaredAnnotations; + } + +} diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java index 6997a427467..b4b22ded16b 100644 --- a/jdk/src/share/classes/java/net/URI.java +++ b/jdk/src/share/classes/java/net/URI.java @@ -1694,6 +1694,13 @@ public final class URI return c; } + // US-ASCII only + private static int toUpper(char c) { + if ((c >= 'a') && (c <= 'z')) + return c - ('a' - 'A'); + return c; + } + private static boolean equal(String s, String t) { if (s == t) return true; if ((s != null) && (t != null)) { @@ -1744,7 +1751,26 @@ public final class URI private static int hash(int hash, String s) { if (s == null) return hash; - return hash * 127 + s.hashCode(); + return s.indexOf('%') < 0 ? hash * 127 + s.hashCode() + : normalizedHash(hash, s); + } + + + private static int normalizedHash(int hash, String s) { + int h = 0; + for (int index = 0; index < s.length(); index++) { + char ch = s.charAt(index); + h = 31 * h + ch; + if (ch == '%') { + /* + * Process the next two encoded characters + */ + for (int i = index + 1; i < index + 3; i++) + h = 31 * h + toUpper(s.charAt(i)); + index += 2; + } + } + return hash * 127 + h; } // US-ASCII only diff --git a/jdk/src/share/classes/java/net/URL.java b/jdk/src/share/classes/java/net/URL.java index a17fa946aa4..62271037126 100644 --- a/jdk/src/share/classes/java/net/URL.java +++ b/jdk/src/share/classes/java/net/URL.java @@ -38,17 +38,21 @@ import sun.security.util.SecurityConstants; * directory, or it can be a reference to a more complicated object, * such as a query to a database or to a search engine. More * information on the types of URLs and their formats can be found at: - *
- * - * http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html - *
+ * + * Types of URL *

- * In general, a URL can be broken into several parts. The previous - * example of a URL indicates that the protocol to use is + * In general, a URL can be broken into several parts. Consider the + * following example: + *

+ *     http://www.example.com/docs/resource1.html
+ * 
+ *

+ * The URL above indicates that the protocol to use is * http (HyperText Transfer Protocol) and that the * information resides on a host machine named - * www.socs.uts.edu.au. The information on that host - * machine is named /MosaicDocs-old/url-primer.html. The exact + * www.example.com. The information on that host + * machine is named /docs/resource1.html. The exact * meaning of this name on the host machine is both protocol * dependent and host dependent. The information normally resides in * a file, but it could be generated on the fly. This component of @@ -61,7 +65,7 @@ import sun.security.util.SecurityConstants; * http is 80. An alternative port could be * specified as: *

- *     http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
+ *     http://www.example.com:1080/docs/resource1.html
  * 
*

* The syntax of URL is defined by + * The specified {@code password} is cloned before it is stored in the + * new {@code PasswordProtection} object. + * + * @param password the password, which may be {@code null} + * @param protectionAlgorithm the encryption algorithm name, for + * example, {@code PBEWithHmacSHA256AndAES_256}. + * See the Cipher section in the + * Java Cryptography Architecture Standard Algorithm Name + * Documentation + * for information about standard encryption algorithm names. + * @param protectionParameters the encryption algorithm parameter + * specification, which may be {@code null} + * @exception NullPointerException if {@code protectionAlgorithm} is + * {@code null} + * + * @since 1.8 + */ + public PasswordProtection(char[] password, String protectionAlgorithm, + AlgorithmParameterSpec protectionParameters) { + if (protectionAlgorithm == null) { + throw new NullPointerException("invalid null input"); + } + this.password = (password == null) ? null : password.clone(); + this.protectionAlgorithm = protectionAlgorithm; + this.protectionParameters = protectionParameters; + } + + /** + * Gets the name of the protection algorithm. + * If none was set then the keystore provider will use its default + * protection algorithm. The name of the default protection algorithm + * for a given keystore type is set using the + * {@code 'keystore..keyProtectionAlgorithm'} security property. + * For example, the + * {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the + * name of the default key protection algorithm used for PKCS12 + * keystores. If the security property is not set, an + * implementation-specific algorithm will be used. + * + * @return the algorithm name, or {@code null} if none was set + * + * @since 1.8 + */ + public String getProtectionAlgorithm() { + return protectionAlgorithm; + } + + /** + * Gets the parameters supplied for the protection algorithm. + * + * @return the algorithm parameter specification, or {@code null}, + * if none was set + * + * @since 1.8 + */ + public AlgorithmParameterSpec getProtectionParameters() { + return protectionParameters; } /** @@ -336,7 +406,44 @@ public class KeyStore { * * @since 1.5 */ - public static interface Entry { } + public static interface Entry { + + /** + * Retrieves the attributes associated with an entry. + *

+ * The default implementation returns an empty {@code Set}. + * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + public default Set getAttributes() { + return Collections.emptySet(); + } + + /** + * An attribute associated with a keystore entry. + * It comprises a name and one or more values. + * + * @since 1.8 + */ + public interface Attribute { + /** + * Returns the attribute's name. + * + * @return the attribute name + */ + public String getName(); + + /** + * Returns the attribute's value. + * Multi-valued attributes encode their values as a single string. + * + * @return the attribute value + */ + public String getValue(); + } + } /** * A KeyStore entry that holds a PrivateKey @@ -348,6 +455,7 @@ public class KeyStore { private final PrivateKey privKey; private final Certificate[] chain; + private final Set attributes; /** * Constructs a PrivateKeyEntry with a @@ -374,7 +482,39 @@ public class KeyStore { * in the end entity Certificate (at index 0) */ public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) { - if (privateKey == null || chain == null) { + this(privateKey, chain, Collections.emptySet()); + } + + /** + * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and + * corresponding certificate chain and associated entry attributes. + * + *

The specified {@code chain} and {@code attributes} are cloned + * before they are stored in the new {@code PrivateKeyEntry} object. + * + * @param privateKey the {@code PrivateKey} + * @param chain an array of {@code Certificate}s + * representing the certificate chain. + * The chain must be ordered and contain a + * {@code Certificate} at index 0 + * corresponding to the private key. + * @param attributes the attributes + * + * @exception NullPointerException if {@code privateKey}, {@code chain} + * or {@code attributes} is {@code null} + * @exception IllegalArgumentException if the specified chain has a + * length of 0, if the specified chain does not contain + * {@code Certificate}s of the same type, + * or if the {@code PrivateKey} algorithm + * does not match the algorithm of the {@code PublicKey} + * in the end entity {@code Certificate} (at index 0) + * + * @since 1.8 + */ + public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain, + Set attributes) { + + if (privateKey == null || chain == null || attributes == null) { throw new NullPointerException("invalid null input"); } if (chain.length == 0) { @@ -409,6 +549,9 @@ public class KeyStore { } else { this.chain = clonedChain; } + + this.attributes = + Collections.unmodifiableSet(new HashSet<>(attributes)); } /** @@ -449,6 +592,19 @@ public class KeyStore { return chain[0]; } + /** + * Retrieves the attributes associated with an entry. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + @Override + public Set getAttributes() { + return attributes; + } + /** * Returns a string representation of this PrivateKeyEntry. * @return a string representation of this PrivateKeyEntry. @@ -474,6 +630,7 @@ public class KeyStore { public static final class SecretKeyEntry implements Entry { private final SecretKey sKey; + private final Set attributes; /** * Constructs a SecretKeyEntry with a @@ -489,6 +646,32 @@ public class KeyStore { throw new NullPointerException("invalid null input"); } this.sKey = secretKey; + this.attributes = Collections.emptySet(); + } + + /** + * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and + * associated entry attributes. + * + *

The specified {@code attributes} is cloned before it is stored + * in the new {@code SecretKeyEntry} object. + * + * @param secretKey the {@code SecretKey} + * @param attributes the attributes + * + * @exception NullPointerException if {@code secretKey} or + * {@code attributes} is {@code null} + * + * @since 1.8 + */ + public SecretKeyEntry(SecretKey secretKey, Set attributes) { + + if (secretKey == null || attributes == null) { + throw new NullPointerException("invalid null input"); + } + this.sKey = secretKey; + this.attributes = + Collections.unmodifiableSet(new HashSet<>(attributes)); } /** @@ -500,6 +683,19 @@ public class KeyStore { return sKey; } + /** + * Retrieves the attributes associated with an entry. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + @Override + public Set getAttributes() { + return attributes; + } + /** * Returns a string representation of this SecretKeyEntry. * @return a string representation of this SecretKeyEntry. @@ -518,6 +714,7 @@ public class KeyStore { public static final class TrustedCertificateEntry implements Entry { private final Certificate cert; + private final Set attributes; /** * Constructs a TrustedCertificateEntry with a @@ -533,6 +730,32 @@ public class KeyStore { throw new NullPointerException("invalid null input"); } this.cert = trustedCert; + this.attributes = Collections.emptySet(); + } + + /** + * Constructs a {@code TrustedCertificateEntry} with a + * trusted {@code Certificate} and associated entry attributes. + * + *

The specified {@code attributes} is cloned before it is stored + * in the new {@code TrustedCertificateEntry} object. + * + * @param trustedCert the trusted {@code Certificate} + * @param attributes the attributes + * + * @exception NullPointerException if {@code trustedCert} or + * {@code attributes} is {@code null} + * + * @since 1.8 + */ + public TrustedCertificateEntry(Certificate trustedCert, + Set attributes) { + if (trustedCert == null || attributes == null) { + throw new NullPointerException("invalid null input"); + } + this.cert = trustedCert; + this.attributes = + Collections.unmodifiableSet(new HashSet<>(attributes)); } /** @@ -544,6 +767,19 @@ public class KeyStore { return cert; } + /** + * Retrieves the attributes associated with an entry. + *

+ * + * @return an unmodifiable {@code Set} of attributes, possibly empty + * + * @since 1.8 + */ + @Override + public Set getAttributes() { + return attributes; + } + /** * Returns a string representation of this TrustedCertificateEntry. * @return a string representation of this TrustedCertificateEntry. diff --git a/jdk/src/share/classes/java/security/PKCS12Attribute.java b/jdk/src/share/classes/java/security/PKCS12Attribute.java new file mode 100644 index 00000000000..e3898628820 --- /dev/null +++ b/jdk/src/share/classes/java/security/PKCS12Attribute.java @@ -0,0 +1,285 @@ +/* + * 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 java.security; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.regex.Pattern; +import sun.security.util.*; + +/** + * An attribute associated with a PKCS12 keystore entry. + * The attribute name is an ASN.1 Object Identifier and the attribute + * value is a set of ASN.1 types. + * + * @since 1.8 + */ +public final class PKCS12Attribute implements KeyStore.Entry.Attribute { + + private static final Pattern COLON_SEPARATED_HEX_PAIRS = + Pattern.compile("^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+$"); + private String name; + private String value; + private byte[] encoded; + private int hashValue = -1; + + /** + * Constructs a PKCS12 attribute from its name and value. + * The name is an ASN.1 Object Identifier represented as a list of + * dot-separated integers. + * A string value is represented as the string itself. + * A binary value is represented as a string of colon-separated + * pairs of hexadecimal digits. + * Multi-valued attributes are represented as a comma-separated + * list of values, enclosed in square brackets. See + * {@link Arrays#toString(java.lang.Object[])}. + *

+ * A string value will be DER-encoded as an ASN.1 UTF8String and a + * binary value will be DER-encoded as an ASN.1 Octet String. + * + * @param name the attribute's identifier + * @param value the attribute's value + * + * @exception NullPointerException if {@code name} or {@code value} + * is {@code null} + * @exception IllegalArgumentException if {@code name} or + * {@code value} is incorrectly formatted + */ + public PKCS12Attribute(String name, String value) { + if (name == null || value == null) { + throw new NullPointerException(); + } + // Validate name + ObjectIdentifier type; + try { + type = new ObjectIdentifier(name); + } catch (IOException e) { + throw new IllegalArgumentException("Incorrect format: name", e); + } + this.name = name; + + // Validate value + int length = value.length(); + String[] values; + if (value.charAt(0) == '[' && value.charAt(length - 1) == ']') { + values = value.substring(1, length - 1).split(", "); + } else { + values = new String[]{ value }; + } + this.value = value; + + try { + this.encoded = encode(type, values); + } catch (IOException e) { + throw new IllegalArgumentException("Incorrect format: value", e); + } + } + + /** + * Constructs a PKCS12 attribute from its ASN.1 DER encoding. + * The DER encoding is specified by the following ASN.1 definition: + *

+     *
+     * Attribute ::= SEQUENCE {
+     *     type   AttributeType,
+     *     values SET OF AttributeValue
+     * }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY defined by type
+     *
+     * 
+ * + * @param encoded the attribute's ASN.1 DER encoding. It is cloned + * to prevent subsequent modificaion. + * + * @exception NullPointerException if {@code encoded} is + * {@code null} + * @exception IllegalArgumentException if {@code encoded} is + * incorrectly formatted + */ + public PKCS12Attribute(byte[] encoded) { + if (encoded == null) { + throw new NullPointerException(); + } + this.encoded = encoded.clone(); + + try { + parse(encoded); + } catch (IOException e) { + throw new IllegalArgumentException("Incorrect format: encoded", e); + } + } + + /** + * Returns the attribute's ASN.1 Object Identifier represented as a + * list of dot-separated integers. + * + * @return the attribute's identifier + */ + @Override + public String getName() { + return name; + } + + /** + * Returns the attribute's ASN.1 DER-encoded value as a string. + * An ASN.1 DER-encoded value is returned in one of the following + * {@code String} formats: + *
    + *
  • the DER encoding of a basic ASN.1 type that has a natural + * string representation is returned as the string itself. + * Such types are currently limited to BOOLEAN, INTEGER, + * OBJECT IDENTIFIER, UTCTime, GeneralizedTime and the + * following six ASN.1 string types: UTF8String, + * PrintableString, T61String, IA5String, BMPString and + * GeneralString. + *
  • the DER encoding of any other ASN.1 type is not decoded but + * returned as a binary string of colon-separated pairs of + * hexadecimal digits. + *
+ * Multi-valued attributes are represented as a comma-separated + * list of values, enclosed in square brackets. See + * {@link Arrays#toString(java.lang.Object[])}. + * + * @return the attribute value's string encoding + */ + @Override + public String getValue() { + return value; + } + + /** + * Returns the attribute's ASN.1 DER encoding. + * + * @return a clone of the attribute's DER encoding + */ + public byte[] getEncoded() { + return encoded.clone(); + } + + /** + * Compares this {@code PKCS12Attribute} and a specified object for + * equality. + * + * @param obj the comparison object + * + * @return true if {@code obj} is a {@code PKCS12Attribute} and + * their DER encodings are equal. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PKCS12Attribute)) { + return false; + } + return Arrays.equals(encoded, ((PKCS12Attribute) obj).getEncoded()); + } + + /** + * Returns the hashcode for this {@code PKCS12Attribute}. + * The hash code is computed from its DER encoding. + * + * @return the hash code + */ + @Override + public int hashCode() { + if (hashValue == -1) { + Arrays.hashCode(encoded); + } + return hashValue; + } + + /** + * Returns a string representation of this {@code PKCS12Attribute}. + * + * @return a name/value pair separated by an 'equals' symbol + */ + @Override + public String toString() { + return (name + "=" + value); + } + + private byte[] encode(ObjectIdentifier type, String[] values) + throws IOException { + DerOutputStream attribute = new DerOutputStream(); + attribute.putOID(type); + DerOutputStream attrContent = new DerOutputStream(); + for (String value : values) { + if (COLON_SEPARATED_HEX_PAIRS.matcher(value).matches()) { + byte[] bytes = + new BigInteger(value.replace(":", ""), 16).toByteArray(); + if (bytes[0] == 0) { + bytes = Arrays.copyOfRange(bytes, 1, bytes.length); + } + attrContent.putOctetString(bytes); + } else { + attrContent.putUTF8String(value); + } + } + attribute.write(DerValue.tag_Set, attrContent); + DerOutputStream attributeValue = new DerOutputStream(); + attributeValue.write(DerValue.tag_Sequence, attribute); + + return attributeValue.toByteArray(); + } + + private void parse(byte[] encoded) throws IOException { + DerInputStream attributeValue = new DerInputStream(encoded); + DerValue[] attrSeq = attributeValue.getSequence(2); + ObjectIdentifier type = attrSeq[0].getOID(); + DerInputStream attrContent = + new DerInputStream(attrSeq[1].toByteArray()); + DerValue[] attrValueSet = attrContent.getSet(1); + String[] values = new String[attrValueSet.length]; + String printableString; + for (int i = 0; i < attrValueSet.length; i++) { + if (attrValueSet[i].tag == DerValue.tag_OctetString) { + values[i] = Debug.toString(attrValueSet[i].getOctetString()); + } else if ((printableString = attrValueSet[i].getAsString()) + != null) { + values[i] = printableString; + } else if (attrValueSet[i].tag == DerValue.tag_ObjectId) { + values[i] = attrValueSet[i].getOID().toString(); + } else if (attrValueSet[i].tag == DerValue.tag_GeneralizedTime) { + values[i] = attrValueSet[i].getGeneralizedTime().toString(); + } else if (attrValueSet[i].tag == DerValue.tag_UtcTime) { + values[i] = attrValueSet[i].getUTCTime().toString(); + } else if (attrValueSet[i].tag == DerValue.tag_Integer) { + values[i] = attrValueSet[i].getBigInteger().toString(); + } else if (attrValueSet[i].tag == DerValue.tag_Boolean) { + values[i] = String.valueOf(attrValueSet[i].getBoolean()); + } else { + values[i] = Debug.toString(attrValueSet[i].getDataBytes()); + } + } + + this.name = type.toString(); + this.value = values.length == 1 ? values[0] : Arrays.toString(values); + } +} diff --git a/jdk/src/share/classes/java/security/PrivateKey.java b/jdk/src/share/classes/java/security/PrivateKey.java index d836ea36833..7d8a7ea7041 100644 --- a/jdk/src/share/classes/java/security/PrivateKey.java +++ b/jdk/src/share/classes/java/security/PrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2001, 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 @@ -26,13 +26,23 @@ package java.security; /** - *

A private key. This interface contains no methods or constants. - * It merely serves to group (and provide type safety for) all private key - * interfaces. - * + * A private key. + * The purpose of this interface is to group (and provide type safety + * for) all private key interfaces. + *

* Note: The specialized private key interfaces extend this interface. - * See, for example, the DSAPrivateKey interface in - * java.security.interfaces. + * See, for example, the {@code DSAPrivateKey} interface in + * {@link java.security.interfaces}. + *

+ * Implementations should override the default {@code destroy} and + * {@code isDestroyed} methods from the + * {@link javax.security.auth.Destroyable} interface to enable + * sensitive key information to be destroyed, cleared, or in the case + * where such information is immutable, unreferenced. + * Finally, since {@code PrivateKey} is {@code Serializable}, implementations + * should also override + * {@link java.io.ObjectOutputStream#writeObject(java.lang.Object)} + * to prevent keys that have been destroyed from being serialized. * * @see Key * @see PublicKey @@ -46,7 +56,8 @@ package java.security; * @author Josh Bloch */ -public interface PrivateKey extends Key { +public interface PrivateKey extends Key, javax.security.auth.Destroyable { + // Declare serialVersionUID to be compatible with JDK1.1 /** * The class fingerprint that is set to indicate serialization diff --git a/jdk/src/share/classes/java/sql/BatchUpdateException.java b/jdk/src/share/classes/java/sql/BatchUpdateException.java index 19742c82fa7..4d41d471cff 100644 --- a/jdk/src/share/classes/java/sql/BatchUpdateException.java +++ b/jdk/src/share/classes/java/sql/BatchUpdateException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, 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 @@ -25,6 +25,10 @@ package java.sql; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.Arrays; /** @@ -49,6 +53,15 @@ import java.util.Arrays; * commands, the array element for any command * that failed is Statement.EXECUTE_FAILED. *

+ * A JDBC driver implementation should use + * the constructor {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) } instead of + * constructors that take {@code int[]} for the update counts to avoid the + * possibility of overflow. + *

+ * If {@code Statement.executeLargeBatch} method is invoked it is recommended that + * {@code getLargeUpdateCounts} be called instead of {@code getUpdateCounts} + * in order to avoid a possible overflow of the integer update count. * @since 1.2 */ @@ -62,7 +75,11 @@ public class BatchUpdateException extends SQLException { * initialized by a call to the * {@link Throwable#initCause(java.lang.Throwable)} method. *

- * + * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

* @param reason a description of the error * @param SQLState an XOPEN or SQL:2003 code identifying the exception * @param vendorCode an exception code used by a particular @@ -76,11 +93,14 @@ public class BatchUpdateException extends SQLException { * prior to the failure for JDBC drivers that stop processing after a command * failure * @since 1.2 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) */ public BatchUpdateException( String reason, String SQLState, int vendorCode, int[] updateCounts ) { super(reason, SQLState, vendorCode); this.updateCounts = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length); + this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts); } /** @@ -92,7 +112,11 @@ public class BatchUpdateException extends SQLException { * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code * is initialized to 0. *

- * + * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

* @param reason a description of the exception * @param SQLState an XOPEN or SQL:2003 code identifying the exception * @param updateCounts an array of int, with each element @@ -104,6 +128,8 @@ public class BatchUpdateException extends SQLException { * prior to the failure for JDBC drivers that stop processing after a command * failure * @since 1.2 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) */ public BatchUpdateException(String reason, String SQLState, int[] updateCounts) { @@ -119,8 +145,11 @@ public class BatchUpdateException extends SQLException { * SQLState is initialized to null * and the vender code is initialized to 0. *

- * - * + * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

* @param reason a description of the exception * @param updateCounts an array of int, with each element * indicating the update count, Statement.SUCCESS_NO_INFO or @@ -131,6 +160,8 @@ public class BatchUpdateException extends SQLException { * prior to the failure for JDBC drivers that stop processing after a command * failure * @since 1.2 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) */ public BatchUpdateException(String reason, int[] updateCounts) { this(reason, null, 0, updateCounts); @@ -144,7 +175,11 @@ public class BatchUpdateException extends SQLException { * and SQLState are initialized to null and the vendor code * is initialized to 0. *

- * + * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

* @param updateCounts an array of int, with each element * indicating the update count, Statement.SUCCESS_NO_INFO or * Statement.EXECUTE_FAILED for each SQL command in @@ -154,6 +189,8 @@ public class BatchUpdateException extends SQLException { * prior to the failure for JDBC drivers that stop processing after a command * failure * @since 1.2 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) */ public BatchUpdateException(int[] updateCounts) { this(null, null, 0, updateCounts); @@ -169,131 +206,167 @@ public class BatchUpdateException extends SQLException { *

* * @since 1.2 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) */ public BatchUpdateException() { this(null, null, 0, null); } - /** - * Constructs a BatchUpdateException object initialized with - * a given cause. - * The SQLState and updateCounts - * are initialized - * to null and the vendor code is initialized to 0. - * The reason is initialized to null if - * cause==null or to cause.toString() if - * cause!=null. - * @param cause the underlying reason for this SQLException - * (which is saved for later retrieval by the getCause() method); - * may be null indicating the cause is non-existent or unknown. - * @since 1.6 - */ - public BatchUpdateException(Throwable cause) { - this((cause == null ? null : cause.toString()), null, 0, null, cause); - } + /** + * Constructs a BatchUpdateException object initialized with + * a given cause. + * The SQLState and updateCounts + * are initialized + * to null and the vendor code is initialized to 0. + * The reason is initialized to null if + * cause==null or to cause.toString() if + * cause!=null. + * @param cause the underlying reason for this SQLException + * (which is saved for later retrieval by the getCause() method); + * may be null indicating the cause is non-existent or unknown. + * @since 1.6 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) + */ + public BatchUpdateException(Throwable cause) { + this((cause == null ? null : cause.toString()), null, 0, (int[])null, cause); + } - /** - * Constructs a BatchUpdateException object initialized with a - * given cause and updateCounts. - * The SQLState is initialized - * to null and the vendor code is initialized to 0. - * The reason is initialized to null if - * cause==null or to cause.toString() if - * cause!=null. - * - * @param updateCounts an array of int, with each element - * indicating the update count, Statement.SUCCESS_NO_INFO or + /** + * Constructs a BatchUpdateException object initialized with a + * given cause and updateCounts. + * The SQLState is initialized + * to null and the vendor code is initialized to 0. + * The reason is initialized to null if + * cause==null or to cause.toString() if + * cause!=null. + *

+ * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

+ * @param updateCounts an array of int, with each element + * indicating the update count, Statement.SUCCESS_NO_INFO or * Statement.EXECUTE_FAILED for each SQL command in * the batch for JDBC drivers that continue processing * after a command failure; an update count or * Statement.SUCCESS_NO_INFO for each SQL command in the batch * prior to the failure for JDBC drivers that stop processing after a command * failure - * @param cause the underlying reason for this SQLException - * (which is saved for later retrieval by the getCause() method); may be null indicating - * the cause is non-existent or unknown. - * @since 1.6 - */ - public BatchUpdateException(int []updateCounts , Throwable cause) { - this((cause == null ? null : cause.toString()), null, 0, updateCounts, cause); - } + * @param cause the underlying reason for this SQLException + * (which is saved for later retrieval by the getCause() method); may be null indicating + * the cause is non-existent or unknown. + * @since 1.6 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) + */ + public BatchUpdateException(int []updateCounts , Throwable cause) { + this((cause == null ? null : cause.toString()), null, 0, updateCounts, cause); + } - /** - * Constructs a BatchUpdateException object initialized with - * a given reason, cause - * and updateCounts. The SQLState is initialized - * to null and the vendor code is initialized to 0. - * - * @param reason a description of the exception - * @param updateCounts an array of int, with each element - *indicating the update count, Statement.SUCCESS_NO_INFO or + /** + * Constructs a BatchUpdateException object initialized with + * a given reason, cause + * and updateCounts. The SQLState is initialized + * to null and the vendor code is initialized to 0. + *

+ * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

+ * @param reason a description of the exception + * @param updateCounts an array of int, with each element + *indicating the update count, Statement.SUCCESS_NO_INFO or * Statement.EXECUTE_FAILED for each SQL command in * the batch for JDBC drivers that continue processing * after a command failure; an update count or * Statement.SUCCESS_NO_INFO for each SQL command in the batch * prior to the failure for JDBC drivers that stop processing after a command * failure - * @param cause the underlying reason for this SQLException (which is saved for later retrieval by the getCause() method); - * may be null indicating - * the cause is non-existent or unknown. - * @since 1.6 - */ - public BatchUpdateException(String reason, int []updateCounts, Throwable cause) { - this(reason, null, 0, updateCounts, cause); - } + * @param cause the underlying reason for this SQLException (which is saved for later retrieval by the getCause() method); + * may be null indicating + * the cause is non-existent or unknown. + * @since 1.6 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) + */ + public BatchUpdateException(String reason, int []updateCounts, Throwable cause) { + this(reason, null, 0, updateCounts, cause); + } - /** - * Constructs a BatchUpdateException object initialized with - * a given reason, SQLState,cause, and + /** + * Constructs a BatchUpdateException object initialized with + * a given reason, SQLState,cause, and * updateCounts. The vendor code is initialized to 0. - * - * @param reason a description of the exception - * @param SQLState an XOPEN or SQL:2003 code identifying the exception - * @param updateCounts an array of int, with each element - * indicating the update count, Statement.SUCCESS_NO_INFO or + * + * @param reason a description of the exception + * @param SQLState an XOPEN or SQL:2003 code identifying the exception + * @param updateCounts an array of int, with each element + * indicating the update count, Statement.SUCCESS_NO_INFO or * Statement.EXECUTE_FAILED for each SQL command in * the batch for JDBC drivers that continue processing * after a command failure; an update count or * Statement.SUCCESS_NO_INFO for each SQL command in the batch * prior to the failure for JDBC drivers that stop processing after a command * failure - * @param cause the underlying reason for this SQLException (which is saved for later retrieval by the getCause() method); - * may be null indicating - * the cause is non-existent or unknown. - * @since 1.6 - */ - public BatchUpdateException(String reason, String SQLState, - int []updateCounts, Throwable cause) { - this(reason, SQLState, 0, updateCounts, cause); - } + *

+ * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

+ * @param cause the underlying reason for this SQLException + * (which is saved for later retrieval by the getCause() method); + * may be null indicating + * the cause is non-existent or unknown. + * @since 1.6 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) + */ + public BatchUpdateException(String reason, String SQLState, + int []updateCounts, Throwable cause) { + this(reason, SQLState, 0, updateCounts, cause); + } - /** - * Constructs a BatchUpdateException object initialized with - * a given reason, SQLState, vendorCode - * cause and updateCounts. - * - * @param reason a description of the error - * @param SQLState an XOPEN or SQL:2003 code identifying the exception - * @param vendorCode an exception code used by a particular - * database vendor - * @param updateCounts an array of int, with each element - *indicating the update count, Statement.SUCCESS_NO_INFO or + /** + * Constructs a BatchUpdateException object initialized with + * a given reason, SQLState, vendorCode + * cause and updateCounts. + * + * @param reason a description of the error + * @param SQLState an XOPEN or SQL:2003 code identifying the exception + * @param vendorCode an exception code used by a particular + * database vendor + * @param updateCounts an array of int, with each element + *indicating the update count, Statement.SUCCESS_NO_INFO or * Statement.EXECUTE_FAILED for each SQL command in * the batch for JDBC drivers that continue processing * after a command failure; an update count or * Statement.SUCCESS_NO_INFO for each SQL command in the batch * prior to the failure for JDBC drivers that stop processing after a command * failure - * @param cause the underlying reason for this SQLException (which is saved for later retrieval by the getCause() method); - * may be null indicating - * the cause is non-existent or unknown. - * @since 1.6 - */ - public BatchUpdateException(String reason, String SQLState, int vendorCode, + *

+ * Note: There is no validation of {@code updateCounts} for + * overflow and because of this it is recommended that you use the constructor + * {@code BatchUpdateException(String reason, String SQLState, + * int vendorCode, long []updateCounts,Throwable cause) }. + *

+ * @param cause the underlying reason for this SQLException (which is saved for later retrieval by the getCause() method); + * may be null indicating + * the cause is non-existent or unknown. + * @since 1.6 + * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[], + * java.lang.Throwable) + */ + public BatchUpdateException(String reason, String SQLState, int vendorCode, int []updateCounts,Throwable cause) { super(reason, SQLState, vendorCode, cause); this.updateCounts = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length); - } + this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts); + } /** * Retrieves the update count for each update statement in the batch @@ -324,17 +397,168 @@ public class BatchUpdateException extends SQLException { * failed to execute successfully * * @since 1.3 + * @see #getLargeUpdateCounts() */ public int[] getUpdateCounts() { return (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length); } + /** + * Constructs a BatchUpdateException object initialized with + * a given reason, SQLState, vendorCode + * cause and updateCounts. + *

+ * This constructor should be used when the returned update count may exceed + * {@link Integer#MAX_VALUE}. + *

+ * @param reason a description of the error + * @param SQLState an XOPEN or SQL:2003 code identifying the exception + * @param vendorCode an exception code used by a particular + * database vendor + * @param updateCounts an array of long, with each element + *indicating the update count, Statement.SUCCESS_NO_INFO or + * Statement.EXECUTE_FAILED for each SQL command in + * the batch for JDBC drivers that continue processing + * after a command failure; an update count or + * Statement.SUCCESS_NO_INFO for each SQL command in the batch + * prior to the failure for JDBC drivers that stop processing after a command + * failure + * @param cause the underlying reason for this SQLException + * (which is saved for later retrieval by the getCause() method); + * may be null indicating the cause is non-existent or unknown. + * @since 1.8 + */ + public BatchUpdateException(String reason, String SQLState, int vendorCode, + long []updateCounts,Throwable cause) { + super(reason, SQLState, vendorCode, cause); + this.longUpdateCounts = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length); + this.updateCounts = (longUpdateCounts == null) ? null : copyUpdateCount(longUpdateCounts); + } + + /** + * Retrieves the update count for each update statement in the batch + * update that executed successfully before this exception occurred. + * A driver that implements batch updates may or may not continue to + * process the remaining commands in a batch when one of the commands + * fails to execute properly. If the driver continues processing commands, + * the array returned by this method will have as many elements as + * there are commands in the batch; otherwise, it will contain an + * update count for each command that executed successfully before + * the BatchUpdateException was thrown. + *

+ * This method should be used when {@code Statement.executeLargeBatch} is + * invoked and the returned update count may exceed {@link Integer#MAX_VALUE}. + *

+ * @return an array of long containing the update counts + * for the updates that were executed successfully before this error + * occurred. Or, if the driver continues to process commands after an + * error, one of the following for every command in the batch: + *

    + *
  1. an update count + *
  2. Statement.SUCCESS_NO_INFO to indicate that the command + * executed successfully but the number of rows affected is unknown + *
  3. Statement.EXECUTE_FAILED to indicate that the command + * failed to execute successfully + *
+ * @since 1.8 + */ + public long[] getLargeUpdateCounts() { + return (longUpdateCounts == null) ? null : + Arrays.copyOf(longUpdateCounts, longUpdateCounts.length); + } + /** * The array that describes the outcome of a batch execution. * @serial * @since 1.2 */ - private final int[] updateCounts; + private int[] updateCounts; + + /* + * Starting with Java SE 8, JDBC has added support for returning an update + * count > Integer.MAX_VALUE. Because of this the following changes were made + * to BatchUpdateException: + *
    + *
  • Add field longUpdateCounts
  • + *
  • Add Constructorr which takes long[] for update counts
  • + *
  • Add getLargeUpdateCounts method
  • + *
+ * When any of the constructors are called, the int[] and long[] updateCount + * fields are populated by copying the one array to each other. + * + * As the JDBC driver passes in the updateCounts, there has always been the + * possiblity for overflow and BatchUpdateException does not need to account + * for that, it simply copies the arrays. + * + * JDBC drivers should always use the constructor that specifies long[] and + * JDBC application developers should call getLargeUpdateCounts. + */ + + /** + * The array that describes the outcome of a batch execution. + * @serial + * @since 1.8 + */ + private long[] longUpdateCounts; private static final long serialVersionUID = 5977529877145521757L; + + /* + * Utility method to copy int[] updateCount to long[] updateCount + */ + private static long[] copyUpdateCount(int[] uc) { + long[] copy = new long[uc.length]; + for(int i= 0; i< uc.length; i++) { + copy[i] = uc[i]; + } + return copy; + } + + /* + * Utility method to copy long[] updateCount to int[] updateCount. + * No checks for overflow will be done as it is expected a user will call + * getLargeUpdateCounts. + */ + private static int[] copyUpdateCount(long[] uc) { + int[] copy = new int[uc.length]; + for(int i= 0; i< uc.length; i++) { + copy[i] = (int) uc[i]; + } + return copy; + } + /** + * readObject is called to restore the state of the + * {@code BatchUpdateException} from a stream. + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + + ObjectInputStream.GetField fields = s.readFields(); + int[] tmp = (int[])fields.get("updateCounts", null); + long[] tmp2 = (long[])fields.get("longUpdateCounts", null); + if(tmp != null && tmp2 != null && tmp.length != tmp2.length) + throw new InvalidObjectException("update counts are not the expected size"); + if (tmp != null) + updateCounts = tmp.clone(); + if (tmp2 != null) + longUpdateCounts = tmp2.clone(); + if(updateCounts == null && longUpdateCounts != null) + updateCounts = copyUpdateCount(longUpdateCounts); + if(longUpdateCounts == null && updateCounts != null) + longUpdateCounts = copyUpdateCount(updateCounts); + + } + + /** + * writeObject is called to save the state of the {@code BatchUpdateException} + * to a stream. + */ + private void writeObject(ObjectOutputStream s) + throws IOException, ClassNotFoundException { + + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("updateCounts", updateCounts); + fields.put("longUpdateCounts", longUpdateCounts); + s.writeFields(); + } } diff --git a/jdk/src/share/classes/java/sql/CallableStatement.java b/jdk/src/share/classes/java/sql/CallableStatement.java index a86caa69ebb..1200f771dad 100644 --- a/jdk/src/share/classes/java/sql/CallableStatement.java +++ b/jdk/src/share/classes/java/sql/CallableStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -1079,9 +1079,7 @@ public interface CallableStatement extends PreparedStatement { int length) throws SQLException; /** - * Sets the value of the designated parameter with the given object. The second - * argument must be an object type; for integral values, the - * java.lang equivalent objects should be used. + * Sets the value of the designated parameter with the given object. * *

The given Java object will be converted to the given targetSqlType * before being sent to the database. @@ -1109,13 +1107,8 @@ public interface CallableStatement extends PreparedStatement { * @exception SQLException if parameterName does not correspond to a named * parameter; if a database access error occurs or * this method is called on a closed CallableStatement - * @exception SQLFeatureNotSupportedException if targetSqlType is - * a ARRAY, BLOB, CLOB, - * DATALINK, JAVA_OBJECT, NCHAR, - * NCLOB, NVARCHAR, LONGNVARCHAR, - * REF, ROWID, SQLXML - * or STRUCT data type and the JDBC driver does not support - * this data type + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type * @see Types * @see #getObject * @since 1.4 @@ -1125,8 +1118,10 @@ public interface CallableStatement extends PreparedStatement { /** * Sets the value of the designated parameter with the given object. - * This method is like the method setObject - * above, except that it assumes a scale of zero. + * + * This method is similar to {@link #setObject(String parameterName, + * Object x, int targetSqlType, int scaleOrLength)}, + * except that it assumes a scale of zero. * * @param parameterName the name of the parameter * @param x the object containing the input parameter value @@ -1135,13 +1130,8 @@ public interface CallableStatement extends PreparedStatement { * @exception SQLException if parameterName does not correspond to a named * parameter; if a database access error occurs or * this method is called on a closed CallableStatement - * @exception SQLFeatureNotSupportedException if targetSqlType is - * a ARRAY, BLOB, CLOB, - * DATALINK, JAVA_OBJECT, NCHAR, - * NCLOB, NVARCHAR, LONGNVARCHAR, - * REF, ROWID, SQLXML - * or STRUCT data type and the JDBC driver does not support - * this data type + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type * @see #getObject * @since 1.4 */ @@ -1150,8 +1140,6 @@ public interface CallableStatement extends PreparedStatement { /** * Sets the value of the designated parameter with the given object. - * The second parameter must be of type Object; therefore, the - * java.lang equivalent objects should be used for built-in types. * *

The JDBC specification specifies a standard mapping from * Java Object types to SQL types. The given argument @@ -2497,4 +2485,338 @@ public interface CallableStatement extends PreparedStatement { */ public T getObject(String parameterName, Class type) throws SQLException; + //------------------------- JDBC 4.2 ----------------------------------- + + /** + *

Sets the value of the designated parameter with the given object. + * + * If the second argument is an {@code InputStream} then the stream + * must contain the number of bytes specified by scaleOrLength. + * If the second argument is a {@code Reader} then the reader must + * contain the number of characters specified + * by scaleOrLength. If these conditions are not true the driver + * will generate a + * {@code SQLException} when the prepared statement is executed. + * + *

The given Java object will be converted to the given targetSqlType + * before being sent to the database. + * + * 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. + * + *

Note that this method may be used to pass database-specific + * abstract data types. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterName the name of the parameter + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be + * sent to the database. The scale argument may further qualify this type. + * @param scaleOrLength for {@code java.sql.JDBCType.DECIMAL} + * or {@code java.sql.JDBCType.NUMERIC types}, + * this is the number of digits after the decimal point. For + * Java Object types {@code InputStream} and {@code Reader}, + * this is the length + * of the data in the stream or reader. For all other types, + * this value will be ignored. + * @exception SQLException if parameterName does not correspond to a named + * parameter; if a database access error occurs + * or this method is called on a closed {@code CallableStatement} 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 setObject(String parameterName, Object x, SQLType targetSqlType, + int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException("setObject not implemented"); + } + /** + * Sets the value of the designated parameter with the given object. + * + * This method is similar to {@link #setObject(String parameterName, + * Object x, SQLType targetSqlType, int scaleOrLength)}, + * except that it assumes a scale of zero. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterName the name of the parameter + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database + * @exception SQLException if parameterName does not correspond to a named + * parameter; if a database access error occurs + * or this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void setObject(String parameterName, Object x, SQLType targetSqlType) + throws SQLException { + throw new SQLFeatureNotSupportedException("setObject not implemented"); + } + + /** + * Registers the OUT parameter in ordinal position + * {@code parameterIndex} to the JDBC type + * {@code sqlType}. All OUT parameters must be registered + * before a stored procedure is executed. + *

+ * The JDBC type specified by {@code sqlType} for an OUT + * parameter determines the Java type that must be used + * in the {@code get} method to read the value of that parameter. + *

+ * If the JDBC type expected to be returned to this output parameter + * is specific to this particular database, {@code sqlType} + * may be {@code JDBCType.OTHER} or a {@code SQLType} that is supported by + * the JDBC driver. The method + * {@link #getObject} retrieves the value. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterIndex the first parameter is 1, the second is 2, + * and so on + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * If the parameter is of JDBC type {@code JDBCType.NUMERIC} + * or {@code JDBCType.DECIMAL}, the version of + * {@code registerOutParameter} that accepts a scale value + * should be used. + * + * @exception SQLException if the parameterIndex is not valid; + * if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void registerOutParameter(int parameterIndex, SQLType sqlType) + throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } + + /** + * Registers the parameter in ordinal position + * {@code parameterIndex} to be of JDBC type + * {@code sqlType}. All OUT parameters must be registered + * before a stored procedure is executed. + *

+ * The JDBC type specified by {@code sqlType} for an OUT + * parameter determines the Java type that must be used + * in the {@code get} method to read the value of that parameter. + *

+ * This version of {@code registrOutParameter} should be + * used when the parameter is of JDBC type {@code JDBCType.NUMERIC} + * or {@code JDBCType.DECIMAL}. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterIndex the first parameter is 1, the second is 2, + * and so on + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * @param scale the desired number of digits to the right of the + * decimal point. It must be greater than or equal to zero. + * @exception SQLException if the parameterIndex is not valid; + * if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void registerOutParameter(int parameterIndex, SQLType sqlType, + int scale) throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } + /** + * Registers the designated output parameter. + * This version of + * the method {@code registrOutParameter} + * should be used for a user-defined or {@code REF} output parameter. + * Examples + * of user-defined types include: {@code STRUCT}, {@code DISTINCT}, + * {@code JAVA_OBJECT}, and named array types. + *

+ * All OUT parameters must be registered + * before a stored procedure is executed. + *

For a user-defined parameter, the fully-qualified SQL + * type name of the parameter should also be given, while a {@code REF} + * parameter requires that the fully-qualified type name of the + * referenced type be given. A JDBC driver that does not need the + * type code and type name information may ignore it. To be portable, + * however, applications should always provide these values for + * user-defined and {@code REF} parameters. + * + * Although it is intended for user-defined and {@code REF} parameters, + * this method may be used to register a parameter of any JDBC type. + * If the parameter does not have a user-defined or {@code REF} type, the + * typeName parameter is ignored. + * + *

Note: When reading the value of an out parameter, you + * must use the getter method whose Java type corresponds to the + * parameter's registered SQL type. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterIndex the first parameter is 1, the second is 2,... + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * @param typeName the fully-qualified name of an SQL structured type + * @exception SQLException if the parameterIndex is not valid; + * if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void registerOutParameter (int parameterIndex, SQLType sqlType, + String typeName) throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } + + /** + * Registers the OUT parameter named + * parameterName to the JDBC type + * {@code sqlType}. All OUT parameters must be registered + * before a stored procedure is executed. + *

+ * The JDBC type specified by {@code sqlType} for an OUT + * parameter determines the Java type that must be used + * in the {@code get} method to read the value of that parameter. + *

+ * If the JDBC type expected to be returned to this output parameter + * is specific to this particular database, {@code sqlType} + * should be {@code JDBCType.OTHER} or a {@code SQLType} that is supported + * by the JDBC driver.. The method + * {@link #getObject} retrieves the value. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterName the name of the parameter + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * If the parameter is of JDBC type {@code JDBCType.NUMERIC} + * or {@code JDBCType.DECIMAL}, the version of + * {@code registrOutParameter} that accepts a scale value + * should be used. + * @exception SQLException if parameterName does not correspond to a named + * parameter; if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * or if the JDBC driver does not support + * this method + * @since 1.8 + * @see JDBCType + * @see SQLType + */ + default void registerOutParameter(String parameterName, SQLType sqlType) + throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } + + /** + * Registers the parameter named + * parameterName to be of JDBC type + * {@code sqlType}. All OUT parameters must be registered + * before a stored procedure is executed. + *

+ * The JDBC type specified by {@code sqlType} for an OUT + * parameter determines the Java type that must be used + * in the {@code get} method to read the value of that parameter. + *

+ * This version of {@code registrOutParameter} should be + * used when the parameter is of JDBC type {@code JDBCType.NUMERIC} + * or {@code JDBCType.DECIMAL}. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterName the name of the parameter + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * @param scale the desired number of digits to the right of the + * decimal point. It must be greater than or equal to zero. + * @exception SQLException if parameterName does not correspond to a named + * parameter; if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * or if the JDBC driver does not support + * this method + * @since 1.8 + * @see JDBCType + * @see SQLType + */ + default void registerOutParameter(String parameterName, SQLType sqlType, + int scale) throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } + + /** + * Registers the designated output parameter. This version of + * the method {@code registrOutParameter} + * should be used for a user-named or REF output parameter. Examples + * of user-named types include: STRUCT, DISTINCT, JAVA_OBJECT, and + * named array types. + *

+ * All OUT parameters must be registered + * before a stored procedure is executed. + *

+ * For a user-named parameter the fully-qualified SQL + * type name of the parameter should also be given, while a REF + * parameter requires that the fully-qualified type name of the + * referenced type be given. A JDBC driver that does not need the + * type code and type name information may ignore it. To be portable, + * however, applications should always provide these values for + * user-named and REF parameters. + * + * Although it is intended for user-named and REF parameters, + * this method may be used to register a parameter of any JDBC type. + * If the parameter does not have a user-named or REF type, the + * typeName parameter is ignored. + * + *

Note: When reading the value of an out parameter, you + * must use the {@code getXXX} method whose Java type XXX corresponds to the + * parameter's registered SQL type. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterName the name of the parameter + * @param sqlType the JDBC type code defined by {@code SQLType} to use to + * register the OUT Parameter. + * @param typeName the fully-qualified name of an SQL structured type + * @exception SQLException if parameterName does not correspond to a named + * parameter; if a database access error occurs or + * this method is called on a closed {@code CallableStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * or if the JDBC driver does not support this method + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void registerOutParameter (String parameterName, SQLType sqlType, + String typeName) throws SQLException { + throw new SQLFeatureNotSupportedException("registerOutParameter not implemented"); + } } diff --git a/jdk/src/share/classes/java/sql/DatabaseMetaData.java b/jdk/src/share/classes/java/sql/DatabaseMetaData.java index 1ad5ea17358..7330b8eac02 100644 --- a/jdk/src/share/classes/java/sql/DatabaseMetaData.java +++ b/jdk/src/share/classes/java/sql/DatabaseMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, 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 @@ -2522,10 +2522,10 @@ public interface DatabaseMetaData extends Wrapper { *

  • ASC_OR_DESC String => column sort sequence, "A" => ascending, * "D" => descending, may be null if sort sequence is not supported; * null when TYPE is tableIndexStatistic - *
  • CARDINALITY int => When TYPE is tableIndexStatistic, then + *
  • CARDINALITY long => When TYPE is tableIndexStatistic, then * this is the number of rows in the table; otherwise, it is the * number of unique values in the index. - *
  • PAGES int => When TYPE is tableIndexStatisic then + *
  • PAGES long => When TYPE is tableIndexStatisic then * this is the number of pages used for the table, otherwise it * is the number of pages used for the current index. *
  • FILTER_CONDITION String => Filter condition, if any. @@ -2759,7 +2759,7 @@ public interface DatabaseMetaData extends Wrapper { /** * Retrieves whether this database supports batch updates. * - * @return true if this database supports batch upcates; + * @return true if this database supports batch updates; * false otherwise * @exception SQLException if a database access error occurs * @since 1.2 @@ -3652,4 +3652,37 @@ public interface DatabaseMetaData extends Wrapper { * @since 1.7 */ boolean generatedKeyAlwaysReturned() throws SQLException; + + //--------------------------JDBC 4.2 ----------------------------- + + /** + * + * Retrieves the maximum number of bytes this database allows for + * the logical size for a {@code LOB}. + *

    + * The default implementation will return {@code 0} + * + * @return the maximum number of bytes allowed; a result of zero + * means that there is no limit or the limit is not known + * @exception SQLException if a database access error occurs + * @since 1.8 + */ + default long getMaxLogicalLobSize() throws SQLException { + return 0; + } + + /** + * Retrieves whether this database supports REF CURSOR. + *

    + * The default implementation will return {@code false} + * + * @return {@code true} if this database supports REF CURSOR; + * {@code false} otherwise + * @exception SQLException if a database access error occurs + * @since 1.8 + */ + default boolean supportsRefCursors() throws SQLException{ + return false; + } + } diff --git a/jdk/src/share/classes/java/sql/Driver.java b/jdk/src/share/classes/java/sql/Driver.java index 4abc6b3c81f..1682b75c910 100644 --- a/jdk/src/share/classes/java/sql/Driver.java +++ b/jdk/src/share/classes/java/sql/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, 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 @@ -65,10 +65,15 @@ public interface Driver { * driver to connect to the given URL but has trouble connecting to * the database. * - *

    The java.util.Properties argument can be used to pass + *

    The {@code Properties} argument can be used to pass * arbitrary string tag/value pairs as connection arguments. * Normally at least "user" and "password" properties should be - * included in the Properties object. + * included in the {@code Properties} object. + *

    + * Note: If a property is specified as part of the {@code url} and + * is also specified in the {@code Properties} object, it is + * implementation-defined as to which value will take precedence. For + * maximum portability, an application should only specify a property once. * * @param url the URL of the database to which to connect * @param info a list of arbitrary string tag/value pairs as @@ -76,7 +81,8 @@ public interface Driver { * "password" property should be included. * @return a Connection object that represents a * connection to the URL - * @exception SQLException if a database access error occurs + * @exception SQLException if a database access error occurs or the url is + * {@code null} */ Connection connect(String url, java.util.Properties info) throws SQLException; @@ -84,13 +90,14 @@ public interface Driver { /** * Retrieves whether the driver thinks that it can open a connection * to the given URL. Typically drivers will return true if they - * understand the subprotocol specified in the URL and false if + * understand the sub-protocol specified in the URL and false if * they do not. * * @param url the URL of the database * @return true if this driver understands the given URL; * false otherwise - * @exception SQLException if a database access error occurs + * @exception SQLException if a database access error occurs or the url is + * {@code null} */ boolean acceptsURL(String url) throws SQLException; diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java index 4021fa24435..b0ca1cd4dea 100644 --- a/jdk/src/share/classes/java/sql/DriverManager.java +++ b/jdk/src/share/classes/java/sql/DriverManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -172,6 +172,12 @@ public class DriverManager { * Attempts to establish a connection to the given database URL. * The DriverManager attempts to select an appropriate driver from * the set of registered JDBC drivers. + *

    + * Note: If a property is specified as part of the {@code url} and + * is also specified in the {@code Properties} object, it is + * implementation-defined as to which value will take precedence. + * For maximum portability, an application should only specify a + * property once. * * @param url a database url of the form * jdbc:subprotocol:subname @@ -179,7 +185,12 @@ public class DriverManager { * connection arguments; normally at least a "user" and * "password" property should be included * @return a Connection to the URL - * @exception SQLException if a database access error occurs + * @exception SQLException if a database access error occurs or the url is + * {@code null} + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt */ public static Connection getConnection(String url, java.util.Properties info) throws SQLException { @@ -195,6 +206,12 @@ public class DriverManager { * Attempts to establish a connection to the given database URL. * The DriverManager attempts to select an appropriate driver from * the set of registered JDBC drivers. + *

    + * Note: If a property is specified as part of the {@code url} and + * is also specified in the {@code Properties} object, it is + * implementation-defined as to which value will take precedence. + * For maximum portability, an application should only specify a + * property once. * * @param url a database url of the form * jdbc:subprotocol:subname @@ -202,7 +219,12 @@ public class DriverManager { * made * @param password the user's password * @return a connection to the URL - * @exception SQLException if a database access error occurs + * @exception SQLException if a database access error occurs or the url is + * {@code null} + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt */ public static Connection getConnection(String url, String user, String password) throws SQLException { @@ -230,7 +252,12 @@ public class DriverManager { * @param url a database url of the form * jdbc:subprotocol:subname * @return a connection to the URL - * @exception SQLException if a database access error occurs + * @exception SQLException if a database access error occurs or the url is + * {@code null} + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt */ public static Connection getConnection(String url) throws SQLException { @@ -380,7 +407,8 @@ public class DriverManager { /** * Sets the maximum time in seconds that a driver will wait - * while attempting to connect to a database. + * while attempting to connect to a database once the driver has + * been identified. * * @param seconds the login time limit in seconds; zero means there is no limit * @see #getLoginTimeout diff --git a/jdk/src/share/classes/java/sql/JDBCType.java b/jdk/src/share/classes/java/sql/JDBCType.java new file mode 100644 index 00000000000..f1453059605 --- /dev/null +++ b/jdk/src/share/classes/java/sql/JDBCType.java @@ -0,0 +1,251 @@ +/* + * 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 java.sql; + +/** + *

    Defines the constants that are used to identify generic + * SQL types, called JDBC types. + *

    + * @see SQLType + * @since 1.8 + */ +public enum JDBCType implements SQLType { + + /** + * Identifies the generic SQL type {@code BIT}. + */ + BIT(Types.BIT), + /** + * Identifies the generic SQL type {@code TINYINT}. + */ + TINYINT(Types.TINYINT), + /** + * Identifies the generic SQL type {@code SMALLINT}. + */ + SMALLINT(Types.SMALLINT), + /** + * Identifies the generic SQL type {@code INTEGER}. + */ + INTEGER(Types.INTEGER), + /** + * Identifies the generic SQL type {@code BIGINT}. + */ + BIGINT(Types.BIGINT), + /** + * Identifies the generic SQL type {@code FLOAT}. + */ + FLOAT(Types.FLOAT), + /** + * Identifies the generic SQL type {@code REAL}. + */ + REAL(Types.REAL), + /** + * Identifies the generic SQL type {@code DOUBLE}. + */ + DOUBLE(Types.DOUBLE), + /** + * Identifies the generic SQL type {@code NUMERIC}. + */ + NUMERIC(Types.NUMERIC), + /** + * Identifies the generic SQL type {@code DECIMAL}. + */ + DECIMAL(Types.DECIMAL), + /** + * Identifies the generic SQL type {@code CHAR}. + */ + CHAR(Types.CHAR), + /** + * Identifies the generic SQL type {@code VARCHAR}. + */ + VARCHAR(Types.VARCHAR), + /** + * Identifies the generic SQL type {@code LONGVARCHAR}. + */ + LONGVARCHAR(Types.LONGVARCHAR), + /** + * Identifies the generic SQL type {@code DATE}. + */ + DATE(Types.DATE), + /** + * Identifies the generic SQL type {@code TIME}. + */ + TIME(Types.TIME), + /** + * Identifies the generic SQL type {@code TIMESTAMP}. + */ + TIMESTAMP(Types.TIMESTAMP), + /** + * Identifies the generic SQL type {@code BINARY}. + */ + BINARY(Types.BINARY), + /** + * Identifies the generic SQL type {@code VARBINARY}. + */ + VARBINARY(Types.VARBINARY), + /** + * Identifies the generic SQL type {@code LONGVARBINARY}. + */ + LONGVARBINARY(Types.LONGVARBINARY), + /** + * Identifies the generic SQL value {@code NULL}. + */ + NULL(Types.NULL), + /** + * Indicates that the SQL type + * is database-specific and gets mapped to a Java object that can be + * accessed via the methods getObject and setObject. + */ + OTHER(Types.OTHER), + /** + * Indicates that the SQL type + * is database-specific and gets mapped to a Java object that can be + * accessed via the methods getObject and setObject. + */ + JAVA_OBJECT(Types.JAVA_OBJECT), + /** + * Identifies the generic SQL type {@code DISTINCT}. + */ + DISTINCT(Types.DISTINCT), + /** + * Identifies the generic SQL type {@code STRUCT}. + */ + STRUCT(Types.STRUCT), + /** + * Identifies the generic SQL type {@code ARRAY}. + */ + ARRAY(Types.ARRAY), + /** + * Identifies the generic SQL type {@code BLOB}. + */ + BLOB(Types.BLOB), + /** + * Identifies the generic SQL type {@code CLOB}. + */ + CLOB(Types.CLOB), + /** + * Identifies the generic SQL type {@code REF}. + */ + REF(Types.REF), + /** + * Identifies the generic SQL type {@code DATALINK}. + */ + DATALINK(Types.DATALINK), + /** + * Identifies the generic SQL type {@code BOOLEAN}. + */ + BOOLEAN(Types.BOOLEAN), + + /* JDBC 4.0 Types */ + + /** + * Identifies the SQL type {@code ROWID}. + */ + ROWID(Types.ROWID), + /** + * Identifies the generic SQL type {@code NCHAR}. + */ + NCHAR(Types.NCHAR), + /** + * Identifies the generic SQL type {@code NVARCHAR}. + */ + NVARCHAR(Types.NVARCHAR), + /** + * Identifies the generic SQL type {@code LONGNVARCHAR}. + */ + LONGNVARCHAR(Types.LONGNVARCHAR), + /** + * Identifies the generic SQL type {@code NCLOB}. + */ + NCLOB(Types.NCLOB), + /** + * Identifies the generic SQL type {@code SQLXML}. + */ + SQLXML(Types.SQLXML), + + /* JDBC 4.2 Types */ + + /** + * Identifies the generic SQL type {@code REF_CURSOR}. + */ + REF_CURSOR(Types.REF_CURSOR); + + /** + * The Integer value for the JDBCType. It maps to a value in + * {@code Types.java} + */ + private Integer type; + + /** + * Constructor to specify the data type value from {@code Types) for + * this data type. + * @param type The value from {@code Types) for this data type + */ + JDBCType(final Integer type) { + this.type = type; + } + + /** + * Returns the name of the data type. + * @return The name of the data type. + */ + public String getName() { + return name(); + } + /** + * Returns the name of the vendor that supports this data type. + * @return The name of the vendor for this data type which is + * {@literal java.sql} for JDBCType. + */ + public String getVendor() { + return "java.sql"; + } + + /** + * Returns the vendor specific type number for the data type. + * @return An Integer representing the data type. For {@code JDBCType}, + * the value will be the same value as in {@code Types} for the data type. + */ + public Integer getVendorTypeNumber() { + return type; + } + /** + * Returns the {@code JDBCType} that corresponds to the specified + * {@code Types} value + * @param type {@code Types} value + * @return The {@code JDBCType} constant + * @throws IllegalArgumentException if this enum type has no constant with + * the specified {@code Types} value + * @see Types + */ + public static JDBCType valueOf(int type) { + for( JDBCType sqlType : JDBCType.class.getEnumConstants()) { + if(type == sqlType.type) + return sqlType; + } + throw new IllegalArgumentException("Type:" + type + " is not a valid " + + "Types.java value."); + } +} diff --git a/jdk/src/share/classes/java/sql/PreparedStatement.java b/jdk/src/share/classes/java/sql/PreparedStatement.java index b7b8211b533..e4d16e86e6f 100644 --- a/jdk/src/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -388,23 +388,20 @@ public interface PreparedStatement extends Statement { /** * Sets the value of the designated parameter with the given object. - * This method is like the method setObject - * above, except that it assumes a scale of zero. + * + * This method is similar to {@link #setObject(int parameterIndex, + * Object x, int targetSqlType, int scaleOrLength)}, + * except that it assumes a scale of zero. * * @param parameterIndex the first parameter is 1, the second is 2, ... * @param x the object containing the input parameter value * @param targetSqlType the SQL type (as defined in java.sql.Types) to be * sent to the database * @exception SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error occurs or - * this method is called on a closed PreparedStatement - * @exception SQLFeatureNotSupportedException if targetSqlType is - * a ARRAY, BLOB, CLOB, - * DATALINK, JAVA_OBJECT, NCHAR, - * NCLOB, NVARCHAR, LONGNVARCHAR, - * REF, ROWID, SQLXML - * or STRUCT data type and the JDBC driver does not support - * this data type + * marker in the SQL statement; if a database access error occurs or this + * method is called on a closed PreparedStatement + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type * @see Types */ void setObject(int parameterIndex, Object x, int targetSqlType) @@ -412,8 +409,6 @@ public interface PreparedStatement extends Statement { /** *

    Sets the value of the designated parameter using the given object. - * The second parameter must be of type Object; therefore, the - * java.lang equivalent objects should be used for built-in types. * *

    The JDBC specification specifies a standard mapping from * Java Object types to SQL types. The given argument @@ -914,9 +909,7 @@ public interface PreparedStatement extends Statement { void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException; /** - *

    Sets the value of the designated parameter with the given object. The second - * argument must be an object type; for integral values, the - * java.lang equivalent objects should be used. + *

    Sets the value of the designated parameter with the given object. * * If the second argument is an InputStream then the stream must contain * the number of bytes specified by scaleOrLength. If the second argument is a @@ -957,13 +950,8 @@ public interface PreparedStatement extends Statement { * 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 targetSqlType is - * a ARRAY, BLOB, CLOB, - * DATALINK, JAVA_OBJECT, NCHAR, - * NCLOB, NVARCHAR, LONGNVARCHAR, - * REF, ROWID, SQLXML - * or STRUCT data type and the JDBC driver does not support - * this data type + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type * @see Types * * @since 1.6 @@ -1220,5 +1208,114 @@ public interface PreparedStatement extends Statement { void setNClob(int parameterIndex, Reader reader) throws SQLException; + //------------------------- JDBC 4.2 ----------------------------------- + /** + *

    Sets the value of the designated parameter with the given object. + * + * If the second argument is an {@code InputStream} then the stream + * must contain the number of bytes specified by scaleOrLength. + * If the second argument is a {@code Reader} then the reader must + * contain the number of characters specified by scaleOrLength. If these + * conditions are not true the driver will generate a + * {@code SQLException} when the prepared statement is executed. + * + *

    The given Java object will be converted to the given targetSqlType + * before being sent to the database. + * + * 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. + * + *

    Note that this method may be used to pass database-specific + * abstract data types. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterIndex the first parameter is 1, the second is 2, ... + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database. The + * scale argument may further qualify this type. + * @param scaleOrLength for {@code java.sql.JDBCType.DECIMAL} + * or {@code java.sql.JDBCType.NUMERIC types}, + * this is the number of digits after the decimal point. For + * Java Object types {@code InputStream} and {@code Reader}, + * this is the length + * of the data in the stream or reader. For all other types, + * this value will be ignored. + * @exception SQLException if parameterIndex does not correspond to a + * parameter marker in the SQL statement; if a database access error occurs + * or this method is called on a closed {@code PreparedStatement} 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 setObject(int parameterIndex, Object x, SQLType targetSqlType, + int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException("setObject not implemented"); + } + + /** + * Sets the value of the designated parameter with the given object. + * + * This method is similar to {@link #setObject(int parameterIndex, + * Object x, SQLType targetSqlType, int scaleOrLength)}, + * except that it assumes a scale of zero. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param parameterIndex the first parameter is 1, the second is 2, ... + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database + * @exception SQLException if parameterIndex does not correspond to a + * parameter marker in the SQL statement; if a database access error occurs + * or this method is called on a closed {@code PreparedStatement} + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void setObject(int parameterIndex, Object x, SQLType targetSqlType) + throws SQLException { + throw new SQLFeatureNotSupportedException("setObject not implemented"); + } + + /** + * Executes the SQL statement in this PreparedStatement object, + * which must be an SQL Data Manipulation Language (DML) statement, + * such as INSERT, UPDATE or + * DELETE; or an SQL statement that returns nothing, + * such as a DDL statement. + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * The default implementation will throw {@code UnsupportedOperationException} + * + * @return either (1) the row count for SQL Data Manipulation Language + * (DML) statements or (2) 0 for SQL statements that return nothing + * @exception SQLException if a database access error occurs; + * this method is called on a closed PreparedStatement + * or the SQL statement returns a ResultSet object + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * @since 1.8 + */ + default long executeLargeUpdate() throws SQLException { + throw new UnsupportedOperationException("executeLargeUpdate not implemented"); + } } diff --git a/jdk/src/share/classes/java/sql/ResultSet.java b/jdk/src/share/classes/java/sql/ResultSet.java index c4beabac5b1..ab547733128 100644 --- a/jdk/src/share/classes/java/sql/ResultSet.java +++ b/jdk/src/share/classes/java/sql/ResultSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -1834,6 +1834,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { /** * Updates the designated column with an Object value. + * * The updater methods are used to update column values in the * current row or the insert row. The updater methods do not * update the underlying database; instead the updateRow or @@ -1866,6 +1867,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { /** * Updates the designated column with an Object value. + * * The updater methods are used to update column values in the * current row or the insert row. The updater methods do not * update the underlying database; instead the updateRow or @@ -2224,6 +2226,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { /** * Updates the designated column with an Object value. + * * The updater methods are used to update column values in the * current row or the insert row. The updater methods do not * update the underlying database; instead the updateRow or @@ -2256,6 +2259,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { /** * Updates the designated column with an Object value. + * * The updater methods are used to update column values in the * current row or the insert row. The updater methods do not * update the underlying database; instead the updateRow or @@ -4142,4 +4146,145 @@ public interface ResultSet extends Wrapper, AutoCloseable { */ public T getObject(String columnLabel, Class type) throws SQLException; + //------------------------- JDBC 4.2 ----------------------------------- + + /** + * Updates the designated column with an {@code Object} value. + * + * The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not + * update the underlying database; instead the {@code updateRow} or + * {@code insertRow} methods are called to update the database. + *

    + * If the second argument is an {@code InputStream} then the stream must contain + * the number of bytes specified by scaleOrLength. If the second argument is a + * {@code Reader} then the reader must contain the number of characters specified + * by scaleOrLength. If these conditions are not true the driver will generate a + * {@code SQLException} when the statement is executed. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param columnIndex the first column is 1, the second is 2, ... + * @param x the new column value + * @param targetSqlType the SQL type to be sent to the database + * @param scaleOrLength for an object of {@code java.math.BigDecimal} , + * this is the number of digits after the decimal point. For + * Java Object types {@code InputStream} and {@code Reader}, + * this is the length + * of the data in the stream or reader. For all other types, + * this value will be ignored. + * @exception SQLException if the columnIndex is not valid; + * if a database access error occurs; + * the result set concurrency is {@code CONCUR_READ_ONLY} + * or this method is called on a closed result set + * @exception SQLFeatureNotSupportedException if the JDBC driver does not + * support this method; if the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void updateObject(int columnIndex, Object x, + SQLType targetSqlType, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException("updateObject not implemented"); + } + + /** + * Updates the designated column with an {@code Object} value. + * + * The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not + * update the underlying database; instead the {@code updateRow} or + * {@code insertRow} methods are called to update the database. + *

    + * If the second argument is an {@code InputStream} then the stream must + * contain number of bytes specified by scaleOrLength. If the second + * argument is a {@code Reader} then the reader must contain the number + * of characters specified by scaleOrLength. If these conditions are not + * true the driver will generate a + * {@code SQLException} when the statement is executed. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param columnLabel the label for the column specified with the SQL AS + * clause. If the SQL AS clause was not specified, then the label is + * the name of the column + * @param targetSqlType the SQL type to be sent to the database + * @param scaleOrLength for an object of {@code java.math.BigDecimal} , + * this is the number of digits after the decimal point. For + * Java Object types {@code InputStream} and {@code Reader}, + * this is the length + * of the data in the stream or reader. For all other types, + * this value will be ignored. + * @exception SQLException if the columnLabel is not valid; + * if a database access error occurs; + * the result set concurrency is {@code CONCUR_READ_ONLY} + * or this method is called on a closed result set + * @exception SQLFeatureNotSupportedException if the JDBC driver does not + * support this method; if the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void updateObject(String columnLabel, Object x, + SQLType targetSqlType, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException("updateObject not implemented"); + } + + /** + * Updates the designated column with an {@code Object} value. + * + * The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not + * update the underlying database; instead the {@code updateRow} or + * {@code insertRow} methods are called to update the database. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param columnIndex the first column is 1, the second is 2, ... + * @param x the new column value + * @param targetSqlType the SQL type to be sent to the database + * @exception SQLException if the columnIndex is not valid; + * if a database access error occurs; + * the result set concurrency is {@code CONCUR_READ_ONLY} + * or this method is called on a closed result set + * @exception SQLFeatureNotSupportedException if the JDBC driver does not + * support this method; if the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void updateObject(int columnIndex, Object x, SQLType targetSqlType) + throws SQLException { + throw new SQLFeatureNotSupportedException("updateObject not implemented"); + } + + /** + * Updates the designated column with an {@code Object} value. + * + * The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not + * update the underlying database; instead the {@code updateRow} or + * {@code insertRow} methods are called to update the database. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param columnLabel the label for the column specified with the SQL AS + * clause. If the SQL AS clause was not specified, then the label is + * the name of the column + * @param x the new column value + * @param targetSqlType the SQL type to be sent to the database + * @exception SQLException if the columnLabel is not valid; + * if a database access error occurs; + * the result set concurrency is {@code CONCUR_READ_ONLY} + * or this method is called on a closed result set + * @exception SQLFeatureNotSupportedException if the JDBC driver does not + * support this method; if the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void updateObject(String columnLabel, Object x, + SQLType targetSqlType) throws SQLException { + throw new SQLFeatureNotSupportedException("updateObject not implemented"); + } } diff --git a/jdk/src/share/classes/java/sql/SQLTimeoutException.java b/jdk/src/share/classes/java/sql/SQLTimeoutException.java index 57abd3be184..a55ee05a74d 100644 --- a/jdk/src/share/classes/java/sql/SQLTimeoutException.java +++ b/jdk/src/share/classes/java/sql/SQLTimeoutException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, 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 @@ -26,8 +26,10 @@ package java.sql; /** - *

    The subclass of {@link SQLException} thrown when the timeout specified by Statement - * has expired. + *

    The subclass of {@link SQLException} thrown when the timeout specified by + * {@code Statement.setQueryTimeout}, {@code DriverManager.setLoginTimeout}, + * {@code DataSource.setLoginTimeout},{@code XADataSource.setLoginTimeout} + * has expired. *

    This exception does not correspond to a standard SQLState. * * @since 1.6 diff --git a/jdk/src/share/classes/java/sql/SQLType.java b/jdk/src/share/classes/java/sql/SQLType.java new file mode 100644 index 00000000000..c0a2b6a6c5f --- /dev/null +++ b/jdk/src/share/classes/java/sql/SQLType.java @@ -0,0 +1,56 @@ +/* + * 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 java.sql; + +/** + * An object that is used to identify a generic SQL type, called a JDBC type or + * a vendor specific data type. + * + * @since 1.8 + */ +public interface SQLType { + + /** + * Returns the {@code SQLType} name that represents a SQL data type. + * + * @return The name of this {@code SQLType}. + */ + String getName(); + + /** + * Returns the name of the vendor that supports this data type. The value + * returned typically is the package name for this vendor. + * + * @return The name of the vendor for this data type + */ + String getVendor(); + + /** + * Returns the vendor specific type number for the data type. + * + * @return An Integer representing the vendor specific data type + */ + Integer getVendorTypeNumber(); +} diff --git a/jdk/src/share/classes/java/sql/Statement.java b/jdk/src/share/classes/java/sql/Statement.java index d249a2f46aa..34859c52c44 100644 --- a/jdk/src/share/classes/java/sql/Statement.java +++ b/jdk/src/share/classes/java/sql/Statement.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 @@ -183,7 +183,15 @@ public interface Statement extends Wrapper, AutoCloseable { * Sets escape processing on or off. * If escape scanning is on (the default), the driver will do * escape substitution before sending the SQL statement to the database. - * + *

    + * The {@code Connection} and {@code DataSource} property + * {@code escapeProcessing} may be used to change the default escape processing + * behavior. A value of true (the default) enables escape Processing for + * all {@code Statement} objects. A value of false disables escape processing + * for all {@code Statement} objects. The {@code setEscapeProcessing} + * method may be used to specify the escape processing behavior for an + * individual {@code Statement} object. + *

    * Note: Since prepared statements have usually been parsed prior * to making this call, disabling escape processing for * PreparedStatements objects will have no effect. @@ -1060,4 +1068,303 @@ public interface Statement extends Wrapper, AutoCloseable { */ public boolean isCloseOnCompletion() throws SQLException; + + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Retrieves the current result as an update count; if the result + * is a ResultSet object or there are no more results, -1 + * is returned. This method should be called only once per result. + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * The default implementation will throw {@code UnsupportedOperationException} + * + * @return the current result as an update count; -1 if the current result + * is a ResultSet object or there are no more results + * @exception SQLException if a database access error occurs or + * this method is called on a closed Statement + * @see #execute + * @since 1.8 + */ + default long getLargeUpdateCount() throws SQLException { + throw new UnsupportedOperationException("getLargeUpdateCount not implemented"); + } + + /** + * Sets the limit for the maximum number of rows that any + * ResultSet object generated by this Statement + * object can contain to the given number. + * If the limit is exceeded, the excess + * rows are silently dropped. + *

    + * This method should be used when the row limit may exceed + * {@link Integer#MAX_VALUE}. + *

    + * The default implementation will throw {@code UnsupportedOperationException} + * + * @param max the new max rows limit; zero means there is no limit + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement + * or the condition max >= 0 is not satisfied + * @see #getMaxRows + * @since 1.8 + */ + default void setLargeMaxRows(long max) throws SQLException { + throw new UnsupportedOperationException("setLargeMaxRows not implemented"); + } + + /** + * Retrieves the maximum number of rows that a + * ResultSet object produced by this + * Statement object can contain. If this limit is exceeded, + * the excess rows are silently dropped. + *

    + * This method should be used when the returned row limit may exceed + * {@link Integer#MAX_VALUE}. + *

    + * The default implementation will return {@code 0} + * + * @return the current maximum number of rows for a ResultSet + * object produced by this Statement object; + * zero means there is no limit + * @exception SQLException if a database access error occurs or + * this method is called on a closed Statement + * @see #setMaxRows + * @since 1.8 + */ + default long getLargeMaxRows() throws SQLException { + return 0; + } + + /** + * Submits a batch of commands to the database for execution and + * if all commands execute successfully, returns an array of update counts. + * The long elements of the array that is returned are ordered + * to correspond to the commands in the batch, which are ordered + * according to the order in which they were added to the batch. + * The elements in the array returned by the method {@code executeLargeBatch} + * may be one of the following: + *

      + *
    1. A number greater than or equal to zero -- indicates that the + * command was processed successfully and is an update count giving the + * number of rows in the database that were affected by the command's + * execution + *
    2. A value of SUCCESS_NO_INFO -- indicates that the command was + * processed successfully but that the number of rows affected is + * unknown + *

      + * If one of the commands in a batch update fails to execute properly, + * this method throws a BatchUpdateException, and a JDBC + * driver may or may not continue to process the remaining commands in + * the batch. However, the driver's behavior must be consistent with a + * particular DBMS, either always continuing to process commands or never + * continuing to process commands. If the driver continues processing + * after a failure, the array returned by the method + * BatchUpdateException.getLargeUpdateCounts + * will contain as many elements as there are commands in the batch, and + * at least one of the elements will be the following: + *

      + *

    3. A value of EXECUTE_FAILED -- indicates that the command failed + * to execute successfully and occurs only if a driver continues to + * process commands after a command fails + *
    + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * The default implementation will throw {@code UnsupportedOperationException} + * + * @return an array of update counts containing one element for each + * command in the batch. The elements of the array are ordered according + * to the order in which commands were added to the batch. + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement or the + * driver does not support batch statements. Throws {@link BatchUpdateException} + * (a subclass of SQLException) if one of the commands sent to the + * database fails to execute properly or attempts to return a result set. + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * + * @see #addBatch + * @see DatabaseMetaData#supportsBatchUpdates + * @since 1.8 + */ + default long[] executeLargeBatch() throws SQLException { + throw new UnsupportedOperationException("executeLargeBatch not implemented"); + } + + /** + * Executes the given SQL statement, which may be an INSERT, + * UPDATE, or DELETE statement or an + * SQL statement that returns nothing, such as an SQL DDL statement. + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. + *

    + * The default implementation will throw {@code UnsupportedOperationException} + * + * @param sql an SQL Data Manipulation Language (DML) statement, + * such as INSERT, UPDATE or + * DELETE; or an SQL statement that returns nothing, + * such as a DDL statement. + * + * @return either (1) the row count for SQL Data Manipulation Language + * (DML) statements or (2) 0 for SQL statements that return nothing + * + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement, the given + * SQL statement produces a ResultSet object, the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * @since 1.8 + */ + default long executeLargeUpdate(String sql) throws SQLException { + throw new UnsupportedOperationException("executeLargeUpdate not implemented"); + } + + /** + * Executes the given SQL statement and signals the driver with the + * given flag about whether the + * auto-generated keys produced by this Statement object + * should be made available for retrieval. The driver will ignore the + * flag if the SQL statement + * is not an INSERT statement, or an SQL statement able to return + * auto-generated keys (the list of such statements is vendor-specific). + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param sql an SQL Data Manipulation Language (DML) statement, + * such as INSERT, UPDATE or + * DELETE; or an SQL statement that returns nothing, + * such as a DDL statement. + * + * @param autoGeneratedKeys a flag indicating whether auto-generated keys + * should be made available for retrieval; + * one of the following constants: + * Statement.RETURN_GENERATED_KEYS + * Statement.NO_GENERATED_KEYS + * @return either (1) the row count for SQL Data Manipulation Language (DML) statements + * or (2) 0 for SQL statements that return nothing + * + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement, the given + * SQL statement returns a ResultSet object, + * the given constant is not one of those allowed, the method is called on a + * PreparedStatement or CallableStatement + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method with a constant of Statement.RETURN_GENERATED_KEYS + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * @since 1.8 + */ + default long executeLargeUpdate(String sql, int autoGeneratedKeys) + throws SQLException { + throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); + } + + /** + * Executes the given SQL statement and signals the driver that the + * auto-generated keys indicated in the given array should be made available + * for retrieval. This array contains the indexes of the columns in the + * target table that contain the auto-generated keys that should be made + * available. The driver will ignore the array if the SQL statement + * is not an INSERT statement, or an SQL statement able to return + * auto-generated keys (the list of such statements is vendor-specific). + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param sql an SQL Data Manipulation Language (DML) statement, + * such as INSERT, UPDATE or + * DELETE; or an SQL statement that returns nothing, + * such as a DDL statement. + * + * @param columnIndexes an array of column indexes indicating the columns + * that should be returned from the inserted row + * @return either (1) the row count for SQL Data Manipulation Language (DML) statements + * or (2) 0 for SQL statements that return nothing + * + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement, the SQL + * statement returns a ResultSet object,the second argument + * supplied to this method is not an + * int array whose elements are valid column indexes, the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * @since 1.8 + */ + default long executeLargeUpdate(String sql, int columnIndexes[]) throws SQLException { + throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); + } + + /** + * Executes the given SQL statement and signals the driver that the + * auto-generated keys indicated in the given array should be made available + * for retrieval. This array contains the names of the columns in the + * target table that contain the auto-generated keys that should be made + * available. The driver will ignore the array if the SQL statement + * is not an INSERT statement, or an SQL statement able to return + * auto-generated keys (the list of such statements is vendor-specific). + *

    + * This method should be used when the returned row count may exceed + * {@link Integer#MAX_VALUE}. + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. + *

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param sql an SQL Data Manipulation Language (DML) statement, + * such as INSERT, UPDATE or + * DELETE; or an SQL statement that returns nothing, + * such as a DDL statement. + * @param columnNames an array of the names of the columns that should be + * returned from the inserted row + * @return either the row count for INSERT, UPDATE, + * or DELETE statements, or 0 for SQL statements + * that return nothing + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement, the SQL + * statement returns a ResultSet object, the + * second argument supplied to this method is not a String array + * whose elements are valid column names, the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} + * @since 1.8 + */ + default long executeLargeUpdate(String sql, String columnNames[]) + throws SQLException { + throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); + } } diff --git a/jdk/src/share/classes/java/sql/Types.java b/jdk/src/share/classes/java/sql/Types.java index 5b800a926f7..d6fc80a3232 100644 --- a/jdk/src/share/classes/java/sql/Types.java +++ b/jdk/src/share/classes/java/sql/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, 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 @@ -309,6 +309,16 @@ public class Types { */ public static final int SQLXML = 2009; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type {@code REF CURSOR}. + * + * @since 1.8 + */ + public static final int REF_CURSOR = 2012; + // Prevent instantiation private Types() {} } diff --git a/jdk/src/share/classes/java/sql/package.html b/jdk/src/share/classes/java/sql/package.html index 65d906b9a69..d6c97126a2a 100644 --- a/jdk/src/share/classes/java/sql/package.html +++ b/jdk/src/share/classes/java/sql/package.html @@ -2,7 +2,7 @@ + +

    + A new Date and Time API for Java. + The design includes a relatively large number of classes and methods, + however each follows a common design language, especially in method prefixes. + Once the prefixes are understood, the API is relatively simple to comprehend. +

    +

    + The Java Time API is composed of several packages, each with a primary function: +

    +

    + {@link java.time} contains the main API based on the ISO-8601 standard. + The classes defined here represent the principal date-time concepts, + including instants, durations, dates, times, time-zones and periods. + They are based on the ISO calendar system, which is the de facto world + calendar following the proleptic Gregorian rules. + All the classes are immutable and thread-safe. +

    +

    + {@link java.time.temporal} contains the API for accessing the fields and units + of date-time. Units are measurable, such as years, months and hours. + For example, the expression "2 hours later" uses the hours unit. + By contrast, fields are mini-calculations, defining a value. + For example, month-of-year, day-of-week and hour-of-day are all fields. + The set of supported units and fields can be extended by applications if desired. +

    +

    + It also contains the basic part of the calendar neutral API. + This is intended for use by applications that need to use localized calendars. + Ensure that you read the class documentation of {@link java.time.temporal.ChronoLocalDate} + before using non-ISO calendar systems. +

    +

    + {@link java.time.format} contains the API to print and parse fields into date-time + objects and to customize parsing and printing. + Formatters can be created in a variety of ways, including constants, patterns, + localized styles and a builder. + Formatters are immutable and thread-safe. +

    +

    + {@link java.time.zone} contains the API to handle time-zones. + Detailed information is made available about the rules of each time-zone. +

    +

    + The {@link java.time.calendar} package contains alternate calendar systems. + This is intended for use by applications that need to use localized calendars. + Support is provided for the Hijrah, Japanese, Minguo, and Thai Buddhist Calendars. +

    +

    Design notes

    +

    + Where possible, the API avoids the use of null. + All methods define whether they accept or return null in the Javadoc. + As a general rule, methods do not accept or return null. + A key exception is any method that takes an object and returns a boolean, for the purpose + of checking or validating, will generally return false for null. +

    +

    + The API is designed to be type-safe where reasonable in the main high-level API. + Thus, there are separate classes for the distinct concepts of date, time and date-time, plus variants + for offset and time-zones. The core 7 date-time classes, plus Instant, handle the needs of most applications. + Further classes handle other combinations - year, year-month and month-day in a type-safe manner. +

    +

    + In a language like Java, the use of many different types tends to cause API bloat. + This is handled here through the use of common method naming patterns throughout the API. + The common prefixes are 'of', 'get', 'is', 'with', 'plus', 'minus', 'to' and 'at'. + See {@link java.time.LocalDate} for an example of each of these methods. +

    +

    + Following type-safety to its logical conclusion would result in more classes, especially for time - + hour-minute, hour-minute-second and hour-minute-second-nanosecond. + While logically pure, this was not possible in practice, as the additional classes would have + excessively complicated the API. Notably, there would be additional combinations at the offset + and date-time levels, such as offset-date-hour-minute. + To avoid this explosion of types, {@link java.time.LocalTime} is used for all precisions of time. + By contrast, some additional classes were used for dates, such as {@link java.time.temporal.YearMonth}. + This proved necessary, as the API for year-month is significantly different to that for a date, whereas + an absence of nanoseconds in a time can be approximated by returning zero. +

    +

    + Similarly, full type-safety might argue for a separate class for each field in date-time, + such as a class for HourOfDay and another for DayOfMonth. + This approach was tried, but was excessively complicated in the Java language, lacking usability. + A similar problem occurs with periods. + There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes. + However, this yields a lot of classes and a problem of type conversion. + As such, general access to fields and units is not wrapped in a class. +

    +

    + Multiple calendar systems is an awkward addition to the design challenges. + The first principal is that most users want the standard ISO calendar system. + As such, the main classes are ISO-only. The second principal is that most of those that want a + non-ISO calendar system want it for user interaction, thus it is a UI localization issue. + As such, date and time objects should be held as ISO objects in the data model and persistent + storage, only being converted to and from a local calendar for display. + The calendar system would be stored separately in the user preferences. +

    +

    + There are, however, some limited use cases where users believe they need to store and use + dates in arbitrary calendar systems throughout the application. + This is supported by {@link java.time.temporal.ChronoLocalDate}, however it is vital to read + all the associated warnings in the Javadoc of that interface before using it. + In summary, applications that require general interoperation between multiple calendar systems + typically need to be written in a very different way to those only using the ISO calendar, + thus most applications should just use ISO and avoid {@code ChronoLocalDate}. +

    +

    + Throughout all of this, a key goal was to allow date-time fields and units to be defined by applications. + This has been achieved having tried many different designs. +

    + diff --git a/jdk/src/share/classes/java/time/package-info.java b/jdk/src/share/classes/java/time/package-info.java new file mode 100644 index 00000000000..9d06ff9352c --- /dev/null +++ b/jdk/src/share/classes/java/time/package-info.java @@ -0,0 +1,291 @@ +/* + * 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. + */ + +/* + * 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. + */ + +/** + *

    + * The main API for dates, times, instants, and durations. + *

    + *

    + * The classes defined here represent the principal date-time concepts, + * including instants, durations, dates, times, time-zones and periods. + * They are based on the ISO calendar system, which is the de facto world + * calendar following the proleptic Gregorian rules. + * All the classes are immutable and thread-safe. + *

    + *

    + * Each date time instance is composed of fields that are conveniently + * made available by the APIs. For lower level access to the fields refer + * to the {@code java.time.temporal} package. + * Each class includes support for printing and parsing all manner of dates and times. + * Refer to the {@code java.time.format} package for customization options. + *

    + *

    + * The {@code java.time.temporal} package also contains the calendar neutral API + * {@link java.time.temporal.ChronoLocalDate ChronoLocalDate}, + * {@link java.time.temporal.ChronoLocalDateTime ChronoLocalDateTime}, + * {@link java.time.temporal.ChronoZonedDateTime ChronoZonedDateTime} and + * {@link java.time.temporal.Era Era}. + * This is intended for use by applications that need to use localized calendars. + * It is recommended that applications use the ISO-8601 dates and time classes from + * this package across system boundaries, such as to the database or across the network. + * The calendar neutral API should be reserved for interactions with users. + *

    + * + *

    Dates and Times

    + *

    + * {@link java.time.Instant} is essentially a numeric timestamp. + * The current Instant can be retrieved from a {@link java.time.Clock}. + * This is useful for logging and persistence of a point in time + * and has in the past been associated with storing the result + * from {@link java.lang.System#currentTimeMillis()}. + *

    + *

    + * {@link java.time.LocalDate} stores a date without a time. + * This stores a date like '2010-12-03' and could be used to store a birthday. + *

    + *

    + * {@link java.time.LocalTime} stores a time without a date. + * This stores a time like '11:30' and could be used to store an opening or closing time. + *

    + *

    + * {@link java.time.LocalDateTime} stores a date and time. + * This stores a date-time like '2010-12-03T11:30'. + *

    + *

    + * {@link java.time.ZonedDateTime} stores a date and time with a time-zone. + * This is useful if you want to perform accurate calculations of + * dates and times taking into account the {@link java.time.ZoneId}, such as 'Europe/Paris'. + * Where possible, it is recommended to use a simpler class without a time-zone. + * The widespread use of time-zones tends to add considerable complexity to an application. + *

    + * + *

    Duration and Period

    + *

    + * Beyond dates and times, the API also allows the storage of period and durations of time. + * A {@link java.time.Duration} is a simple measure of time along the time-line in nanoseconds. + * A {@link java.time.Period} expresses an amount of time in units meaningful to humans, such as years or hours. + *

    + * + *

    Additional value types

    + *

    + * {@link java.time.Month} stores a month on its own. + * This stores a single month-of-year in isolation, such as 'DECEMBER'. + *

    + *

    + * {@link java.time.DayOfWeek} stores a day-of-week on its own. + * This stores a single day-of-week in isolation, such as 'TUESDAY'. + *

    + *

    + * {@link java.time.temporal.Year} stores a year on its own. + * This stores a single year in isolation, such as '2010'. + *

    + *

    + * {@link java.time.temporal.YearMonth} stores a year and month without a day or time. + * This stores a year and month, such as '2010-12' and could be used for a credit card expiry. + *

    + *

    + * {@link java.time.temporal.MonthDay} stores a month and day without a year or time. + * This stores a month and day-of-month, such as '--12-03' and + * could be used to store an annual event like a birthday without storing the year. + *

    + *

    + * {@link java.time.temporal.OffsetTime} stores a time and offset from UTC without a date. + * This stores a date like '11:30+01:00'. + * The {@link java.time.ZoneOffset ZoneOffset} is of the form '+01:00'. + *

    + *

    + * {@link java.time.temporal.OffsetDate} stores a date and offset from UTC without a time. + * This stores a time like '2010-12-03+01:00'. + *

    + *

    + * {@link java.time.temporal.OffsetDateTime} stores a date and time and offset from UTC. + * This stores a date-time like '2010-12-03T11:30+01:00'. + * This is sometimes found in XML messages and other forms of persistence, + * but contains less information than a full time-zone. + *

    + * + *

    Package specification

    + *

    + * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface + * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown. + * The Javadoc "@param" definition is used to summarise the null-behavior. + * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method. + *

    + *

    + * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException} + * or a {@link java.time.DateTimeException}. + *

    + * + *

    Design notes (non normative)

    + *

    + * The API has been designed to reject null early and to be clear about this behavior. + * A key exception is any method that takes an object and returns a boolean, for the purpose + * of checking or validating, will generally return false for null. + *

    + *

    + * The API is designed to be type-safe where reasonable in the main high-level API. + * Thus, there are separate classes for the distinct concepts of date, time and date-time, + * plus variants for offset and time-zone. + * This can seem like a lot of classes, but most applications can begin with just five date/time types. + *

      + *
    • {@link java.time.Instant} - a timestamp
    • + *
    • {@link java.time.LocalDate} - a date without a time, or any reference to an offset or time-zone
    • + *
    • {@link java.time.LocalTime} - a time without a date, or any reference to an offset or time-zone
    • + *
    • {@link java.time.LocalDateTime} - combines date and time, but still without any offset or time-zone
    • + *
    • {@link java.time.ZonedDateTime} - a "full" date-time with time-zone and resolved offset from UTC/Greenwich
    • + *
    + *

    + * {@code Instant} is the closest equivalent class to {@code java.util.Date}. + * {@code ZonedDateTime} is the closest equivalent class to {@code java.util.GregorianCalendar}. + *

    + *

    + * Where possible, applications should use {@code LocalDate}, {@code LocalTime} and {@code LocalDateTime} + * to better model the domain. For example, a birthday should be stored in a code {@code LocalDate}. + * Bear in mind that any use of a {@linkplain java.time.ZoneId time-zone}, such as 'Europe/Paris', adds + * considerable complexity to a calculation. + * Many applications can be written only using {@code LocalDate}, {@code LocalTime} and {@code Instant}, + * with the time-zone added at the user interface (UI) layer. + *

    + *

    + * The offset-based date-time types, {@code OffsetDate}, {@code OffsetTime} and {@code OffsetDateTime}, + * are intended primarily for use with network protocols and database access. + * For example, most databases cannot automatically store a time-zone like 'Europe/Paris', but + * they can store an offset like '+02:00'. + *

    + *

    + * Classes are also provided for the most important sub-parts of a date, including {@code Month}, + * {@code DayOfWeek}, {@code Year}, {@code YearMonth} and {@code MonthDay}. + * These can be used to model more complex date-time concepts. + * For example, {@code YearMonth} is useful for representing a credit card expiry. + *

    + *

    + * Note that while there are a large number of classes representing different aspects of dates, + * there are relatively few dealing with different aspects of time. + * Following type-safety to its logical conclusion would have resulted in classes for + * hour-minute, hour-minute-second and hour-minute-second-nanosecond. + * While logically pure, this was not a practical option as it would have almost tripled the + * number of classes due to the combinations of date and time. + * Thus, {@code LocalTime} is used for all precisions of time, with zeroes used to imply lower precision. + *

    + *

    + * Following full type-safety to its ultimate conclusion might also argue for a separate class + * for each field in date-time, such as a class for HourOfDay and another for DayOfMonth. + * This approach was tried, but was excessively complicated in the Java language, lacking usability. + * A similar problem occurs with periods. + * There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes. + * However, this yields a lot of classes and a problem of type conversion. + * Thus, the set of date-time types provided is a compromise between purity and practicality. + *

    + *

    + * The API has a relatively large surface area in terms of number of methods. + * This is made manageable through the use of consistent method prefixes. + *

      + *
    • {@code of} - static factory method
    • + *
    • {@code parse} - static factory method focussed on parsing
    • + *
    • {@code get} - gets the value of something
    • + *
    • {@code is} - checks if something is true
    • + *
    • {@code with} - the immutable equivalent of a setter
    • + *
    • {@code plus} - adds an amount to an object
    • + *
    • {@code minus} - subtracts an amount from an object
    • + *
    • {@code to} - converts this object to another type
    • + *
    • {@code at} - combines this object with another, such as {@code date.atTime(time)}
    • + *
    + *

    + * Multiple calendar systems is an awkward addition to the design challenges. + * The first principal is that most users want the standard ISO calendar system. + * As such, the main classes are ISO-only. The second principal is that most of those that want a + * non-ISO calendar system want it for user interaction, thus it is a UI localization issue. + * As such, date and time objects should be held as ISO objects in the data model and persistent + * storage, only being converted to and from a local calendar for display. + * The calendar system would be stored separately in the user preferences. + *

    + *

    + * There are, however, some limited use cases where users believe they need to store and use + * dates in arbitrary calendar systems throughout the application. + * This is supported by {@link java.time.temporal.ChronoLocalDate}, however it is vital to read + * all the associated warnings in the Javadoc of that interface before using it. + * In summary, applications that require general interoperation between multiple calendar systems + * typically need to be written in a very different way to those only using the ISO calendar, + * thus most applications should just use ISO and avoid {@code ChronoLocalDate}. + *

    + *

    + * The API is also designed for user extensibility, as there are many ways of calculating time. + * The {@linkplain java.time.temporal.TemporalField field} and {@linkplain java.time.temporal.TemporalUnit unit} + * API, accessed via {@link java.time.temporal.TemporalAccessor TemporalAccessor} and + * {@link java.time.temporal.Temporal Temporal} provide considerable flexibility to applications. + * In addition, the {@link java.time.temporal.TemporalQuery TemporalQuery} and + * {@link java.time.temporal.TemporalAdjuster TemporalAdjuster} interfaces provide day-to-day + * power, allowing code to read close to business requirements: + *

    + *
    + *   LocalDate customerBirthday = customer.loadBirthdayFromDatabase();
    + *   LocalDate today = LocalDate.now();
    + *   if (customerBirthday.equals(today)) {
    + *     LocalDate specialOfferExpiryDate = today.plusWeeks(2).with(next(FRIDAY));
    + *     customer.sendBirthdaySpecialOffer(specialOfferExpiryDate);
    + *   }
    + *
    + * 
    + * + * @since JDK1.8 + */ +package java.time; diff --git a/jdk/src/share/classes/java/time/temporal/Adjusters.java b/jdk/src/share/classes/java/time/temporal/Adjusters.java new file mode 100644 index 00000000000..45ccfd1a9f5 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Adjusters.java @@ -0,0 +1,502 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +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.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.time.DayOfWeek; +import java.util.Objects; + +/** + * Common implementations of {@code TemporalAdjuster}. + *

    + * This class provides common implementations of {@link TemporalAdjuster}. + * They are especially useful to document the intent of business logic and + * often link well to requirements. + * For example, these two pieces of code do the same thing, but the second + * one is clearer (assuming that there is a static import of this class): + *

    + *  // direct manipulation
    + *  date.withDayOfMonth(1).plusMonths(1).minusDays(1);
    + *  // use of an adjuster from this class
    + *  date.with(lastDayOfMonth());
    + * 
    + * There are two equivalent ways of using a {@code TemporalAdjuster}. + * The first is to invoke the method on the interface directly. + * The second is to use {@link Temporal#with(TemporalAdjuster)}: + *
    + *   // these two lines are equivalent, but the second approach is recommended
    + *   dateTime = adjuster.adjustInto(dateTime);
    + *   dateTime = dateTime.with(adjuster);
    + * 
    + * It is recommended to use the second approach, {@code with(TemporalAdjuster)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * This is a thread-safe utility class. + * All returned adjusters are immutable and thread-safe. + * + * @since 1.8 + */ +public final class Adjusters { + + /** + * Private constructor since this is a utility class. + */ + private Adjusters() { + } + + //----------------------------------------------------------------------- + /** + * Returns the "first day of month" adjuster, which returns a new date set to + * the first day of the current month. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2011-01-01.
    + * The input 2011-02-15 will return 2011-02-01. + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  temporal.with(DAY_OF_MONTH, 1);
    +     * 
    + * + * @return the first day-of-month adjuster, not null + */ + public static TemporalAdjuster firstDayOfMonth() { + return Impl.FIRST_DAY_OF_MONTH; + } + + /** + * Returns the "last day of month" adjuster, which returns a new date set to + * the last day of the current month. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2011-01-31.
    + * The input 2011-02-15 will return 2011-02-28.
    + * The input 2012-02-15 will return 2012-02-29 (leap year).
    + * The input 2011-04-15 will return 2011-04-30. + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  long lastDay = temporal.range(DAY_OF_MONTH).getMaximum();
    +     *  temporal.with(DAY_OF_MONTH, lastDay);
    +     * 
    + * + * @return the last day-of-month adjuster, not null + */ + public static TemporalAdjuster lastDayOfMonth() { + return Impl.LAST_DAY_OF_MONTH; + } + + /** + * Returns the "first day of next month" adjuster, which returns a new date set to + * the first day of the next month. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2011-02-01.
    + * The input 2011-02-15 will return 2011-03-01. + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
    +     * 
    + * + * @return the first day of next month adjuster, not null + */ + public static TemporalAdjuster firstDayOfNextMonth() { + return Impl.FIRST_DAY_OF_NEXT_MONTH; + } + + //----------------------------------------------------------------------- + /** + * Returns the "first day of year" adjuster, which returns a new date set to + * the first day of the current year. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2011-01-01.
    + * The input 2011-02-15 will return 2011-01-01.
    + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  temporal.with(DAY_OF_YEAR, 1);
    +     * 
    + * + * @return the first day-of-year adjuster, not null + */ + public static TemporalAdjuster firstDayOfYear() { + return Impl.FIRST_DAY_OF_YEAR; + } + + /** + * Returns the "last day of year" adjuster, which returns a new date set to + * the last day of the current year. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2011-12-31.
    + * The input 2011-02-15 will return 2011-12-31.
    + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  long lastDay = temporal.range(DAY_OF_YEAR).getMaximum();
    +     *  temporal.with(DAY_OF_YEAR, lastDay);
    +     * 
    + * + * @return the last day-of-year adjuster, not null + */ + public static TemporalAdjuster lastDayOfYear() { + return Impl.LAST_DAY_OF_YEAR; + } + + /** + * Returns the "first day of next year" adjuster, which returns a new date set to + * the first day of the next year. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 will return 2012-01-01. + *

    + * The behavior is suitable for use with most calendar systems. + * It is equivalent to: + *

    +     *  temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
    +     * 
    + * + * @return the first day of next month adjuster, not null + */ + public static TemporalAdjuster firstDayOfNextYear() { + return Impl.FIRST_DAY_OF_NEXT_YEAR; + } + + //----------------------------------------------------------------------- + /** + * Enum implementing the adjusters. + */ + private static class Impl implements TemporalAdjuster { + /** First day of month adjuster. */ + private static final Impl FIRST_DAY_OF_MONTH = new Impl(0); + /** Last day of month adjuster. */ + private static final Impl LAST_DAY_OF_MONTH = new Impl(1); + /** First day of next month adjuster. */ + private static final Impl FIRST_DAY_OF_NEXT_MONTH = new Impl(2); + /** First day of year adjuster. */ + private static final Impl FIRST_DAY_OF_YEAR = new Impl(3); + /** Last day of year adjuster. */ + private static final Impl LAST_DAY_OF_YEAR = new Impl(4); + /** First day of next month adjuster. */ + private static final Impl FIRST_DAY_OF_NEXT_YEAR = new Impl(5); + /** The ordinal. */ + private final int ordinal; + private Impl(int ordinal) { + this.ordinal = ordinal; + } + @Override + public Temporal adjustInto(Temporal temporal) { + switch (ordinal) { + case 0: return temporal.with(DAY_OF_MONTH, 1); + case 1: return temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum()); + case 2: return temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS); + case 3: return temporal.with(DAY_OF_YEAR, 1); + case 4: return temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum()); + case 5: return temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS); + } + throw new IllegalStateException("Unreachable"); + } + } + + //----------------------------------------------------------------------- + /** + * Returns the first in month adjuster, which returns a new date + * in the same month with the first matching day-of-week. + * This is used for expressions like 'first Tuesday in March'. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-12-15 for (MONDAY) will return 2011-12-05.
    + * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.
    + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields + * and the {@code DAYS} unit, and assumes a seven day week. + * + * @param dayOfWeek the day-of-week, not null + * @return the first in month adjuster, not null + */ + public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) { + Objects.requireNonNull(dayOfWeek, "dayOfWeek"); + return new DayOfWeekInMonth(1, dayOfWeek); + } + + /** + * Returns the last in month adjuster, which returns a new date + * in the same month with the last matching day-of-week. + * This is used for expressions like 'last Tuesday in March'. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-12-15 for (MONDAY) will return 2011-12-26.
    + * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.
    + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields + * and the {@code DAYS} unit, and assumes a seven day week. + * + * @param dayOfWeek the day-of-week, not null + * @return the first in month adjuster, not null + */ + public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) { + Objects.requireNonNull(dayOfWeek, "dayOfWeek"); + return new DayOfWeekInMonth(-1, dayOfWeek); + } + + /** + * Returns the day-of-week in month adjuster, which returns a new date + * in the same month with the ordinal day-of-week. + * This is used for expressions like the 'second Tuesday in March'. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.
    + * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.
    + * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.
    + * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.
    + * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.
    + * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).
    + * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).
    + * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).
    + * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).
    + *

    + * For a positive or zero ordinal, the algorithm is equivalent to finding the first + * day-of-week that matches within the month and then adding a number of weeks to it. + * For a negative ordinal, the algorithm is equivalent to finding the last + * day-of-week that matches within the month and then subtracting a number of weeks to it. + * The ordinal number of weeks is not validated and is interpreted leniently + * according to this algorithm. This definition means that an ordinal of zero finds + * the last matching day-of-week in the previous month. + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields + * and the {@code DAYS} unit, and assumes a seven day week. + * + * @param ordinal the week within the month, unbound but typically from -5 to 5 + * @param dayOfWeek the day-of-week, not null + * @return the day-of-week in month adjuster, not null + * @throws IllegalArgumentException if the ordinal is invalid + */ + public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) { + Objects.requireNonNull(dayOfWeek, "dayOfWeek"); + return new DayOfWeekInMonth(ordinal, dayOfWeek); + } + + /** + * Class implementing day-of-week in month adjuster. + */ + private static final class DayOfWeekInMonth implements TemporalAdjuster { + /** The ordinal. */ + private final int ordinal; + /** The day-of-week value, from 1 to 7. */ + private final int dowValue; + + private DayOfWeekInMonth(int ordinal, DayOfWeek dow) { + super(); + this.ordinal = ordinal; + this.dowValue = dow.getValue(); + } + @Override + public Temporal adjustInto(Temporal temporal) { + if (ordinal >= 0) { + Temporal temp = temporal.with(DAY_OF_MONTH, 1); + int curDow = temp.get(DAY_OF_WEEK); + int dowDiff = (dowValue - curDow + 7) % 7; + dowDiff += (ordinal - 1L) * 7L; // safe from overflow + return temp.plus(dowDiff, DAYS); + } else { + Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum()); + int curDow = temp.get(DAY_OF_WEEK); + int daysDiff = dowValue - curDow; + daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff)); + daysDiff -= (-ordinal - 1L) * 7L; // safe from overflow + return temp.plus(daysDiff, DAYS); + } + } + } + + //----------------------------------------------------------------------- + /** + * Returns the next day-of-week adjuster, which adjusts the date to the + * first occurrence of the specified day-of-week after the date being adjusted. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).
    + * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).
    + * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later). + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, + * and assumes a seven day week. + * + * @param dayOfWeek the day-of-week to move the date to, not null + * @return the next day-of-week adjuster, not null + */ + public static TemporalAdjuster next(DayOfWeek dayOfWeek) { + return new RelativeDayOfWeek(2, dayOfWeek); + } + + /** + * Returns the next-or-same day-of-week adjuster, which adjusts the date to the + * first occurrence of the specified day-of-week after the date being adjusted + * unless it is already on that day in which case the same object is returned. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).
    + * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).
    + * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input). + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, + * and assumes a seven day week. + * + * @param dayOfWeek the day-of-week to check for or move the date to, not null + * @return the next-or-same day-of-week adjuster, not null + */ + public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) { + return new RelativeDayOfWeek(0, dayOfWeek); + } + + /** + * Returns the previous day-of-week adjuster, which adjusts the date to the + * first occurrence of the specified day-of-week before the date being adjusted. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).
    + * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).
    + * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier). + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, + * and assumes a seven day week. + * + * @param dayOfWeek the day-of-week to move the date to, not null + * @return the previous day-of-week adjuster, not null + */ + public static TemporalAdjuster previous(DayOfWeek dayOfWeek) { + return new RelativeDayOfWeek(3, dayOfWeek); + } + + /** + * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the + * first occurrence of the specified day-of-week before the date being adjusted + * unless it is already on that day in which case the same object is returned. + *

    + * The ISO calendar system behaves as follows:
    + * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).
    + * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).
    + * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input). + *

    + * The behavior is suitable for use with most calendar systems. + * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, + * and assumes a seven day week. + * + * @param dayOfWeek the day-of-week to check for or move the date to, not null + * @return the previous-or-same day-of-week adjuster, not null + */ + public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) { + return new RelativeDayOfWeek(1, dayOfWeek); + } + + /** + * Implementation of next, previous or current day-of-week. + */ + private static final class RelativeDayOfWeek implements TemporalAdjuster { + /** Whether the current date is a valid answer. */ + private final int relative; + /** The day-of-week value, from 1 to 7. */ + private final int dowValue; + + private RelativeDayOfWeek(int relative, DayOfWeek dayOfWeek) { + Objects.requireNonNull(dayOfWeek, "dayOfWeek"); + this.relative = relative; + this.dowValue = dayOfWeek.getValue(); + } + + @Override + public Temporal adjustInto(Temporal temporal) { + int calDow = temporal.get(DAY_OF_WEEK); + if (relative < 2 && calDow == dowValue) { + return temporal; + } + if ((relative & 1) == 0) { + int daysDiff = calDow - dowValue; + return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS); + } else { + int daysDiff = dowValue - calDow; + return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS); + } + } + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/Chrono.java b/jdk/src/share/classes/java/time/temporal/Chrono.java new file mode 100644 index 00000000000..ff4660884f8 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Chrono.java @@ -0,0 +1,858 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.calendar.HijrahChrono; +import java.time.calendar.JapaneseChrono; +import java.time.calendar.MinguoChrono; +import java.time.calendar.ThaiBuddhistChrono; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A calendar system, used to organize and identify dates. + *

    + * The main date and time API is built on the ISO calendar system. + * This class operates behind the scenes to represent the general concept of a calendar system. + * For example, the Japanese, Minguo, Thai Buddhist and others. + *

    + * Most other calendar systems also operate on the shared concepts of year, month and day, + * linked to the cycles of the Earth around the Sun, and the Moon around the Earth. + * These shared concepts are defined by {@link ChronoField} and are availalbe + * for use by any {@code Chrono} implementation: + *

    + *   LocalDate isoDate = ...
    + *   ChronoLocalDate<ThaiBuddhistChrono> thaiDate = ...
    + *   int isoYear = isoDate.get(ChronoField.YEAR);
    + *   int thaiYear = thaiDate.get(ChronoField.YEAR);
    + * 
    + * As shown, although the date objects are in different calendar systems, represented by different + * {@code Chrono} instances, both can be queried using the same constant on {@code ChronoField}. + * For a full discussion of the implications of this, see {@link ChronoLocalDate}. + * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than + * {@code ChronoLocalDate}. + *

    + * While a {@code Chrono} object typically uses {@code ChronoField} and is based on + * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required. + * A {@code Chrono} instance may represent a totally different kind of calendar system, + * such as the Mayan. + *

    + * In practical terms, the {@code Chrono} instance also acts as a factory. + * The {@link #of(String)} method allows an instance to be looked up by identifier, + * while the {@link #ofLocale(Locale)} method allows lookup by locale. + *

    + * The {@code Chrono} instance provides a set of methods to create {@code ChronoLocalDate} instances. + * The date classes are used to manipulate specific dates. + *

      + *
    • {@link #dateNow() dateNow()} + *
    • {@link #dateNow(Clock) dateNow(clock)} + *
    • {@link #dateNow(ZoneId) dateNow(zone)} + *
    • {@link #date(int, int, int) date(yearProleptic, month, day)} + *
    • {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)} + *
    • {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)} + *
    • {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)} + *
    • {@link #date(TemporalAccessor) date(TemporalAccessor)} + *

    + * + *

    Adding New Calendars

    + * The set of available chronologies can be extended by applications. + * Adding a new calendar system requires the writing of an implementation of + * {@code Chrono}, {@code ChronoLocalDate} and {@code Era}. + * The majority of the logic specific to the calendar system will be in + * {@code ChronoLocalDate}. The {@code Chrono} subclass acts as a factory. + *

    + * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader} + * is used. A file must be added to the {@code META-INF/services} directory with the + * name 'java.time.temporal.Chrono' listing the implementation classes. + * See the ServiceLoader for more details on service loading. + * For lookup by id or calendarType, the system provided calendars are found + * first followed by application provided calendars. + *

    + * Each chronology must define a chronology ID that is unique within the system. + * If the chronology represents a calendar system defined by the + * Unicode Locale Data Markup Language (LDML) specification then that + * calendar type should also be specified. + * + *

    Specification for implementors

    + * This class must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + * + * @param the type of the implementing subclass + * @since 1.8 + */ +public abstract class Chrono> implements Comparable> { + + /** + * Map of available calendars by ID. + */ + private static final ConcurrentHashMap> CHRONOS_BY_ID = new ConcurrentHashMap<>(); + /** + * Map of available calendars by calendar type. + */ + private static final ConcurrentHashMap> CHRONOS_BY_TYPE = new ConcurrentHashMap<>(); + + /** + * Register a Chrono by ID and type for lookup by {@link #of(java.lang.String)}. + * Chronos must not be registered until they are completely constructed. + * Specifically, not in the constructor of Chrono. + * @param chrono the chronology to register; not null + */ + private static void registerChrono(Chrono chrono) { + Chrono prev = CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono); + if (prev == null) { + String type = chrono.getCalendarType(); + if (type != null) { + CHRONOS_BY_TYPE.putIfAbsent(type, chrono); + } + } + } + + /** + * Initialization of the maps from id and type to Chrono. + * The ServiceLoader is used to find and register any implementations + * of {@link javax.time.temporal.Chrono} found in the bootclass loader. + * The built-in chronologies are registered explicitly. + * Calendars configured via the Thread's context classloader are local + * to that thread and are ignored. + *

    + * The initialization is done only once using the registration + * of the ISOChrono as the test and the final step. + * Multiple threads may perform the initialization concurrently. + * Only the first registration of each Chrono is retained by the + * ConcurrentHashMap. + * @return true if the cache was initialized + */ + private static boolean initCache() { + if (CHRONOS_BY_ID.get("ISO") == null) { + // Initialization is incomplete + @SuppressWarnings("rawtypes") + ServiceLoader loader = ServiceLoader.load(Chrono.class, null); + for (Chrono chrono : loader) { + registerChrono(chrono); + } + + // Register these calendars; the ServiceLoader configuration is not used + registerChrono(HijrahChrono.INSTANCE); + registerChrono(JapaneseChrono.INSTANCE); + registerChrono(MinguoChrono.INSTANCE); + registerChrono(ThaiBuddhistChrono.INSTANCE); + + // finally, register ISOChrono to mark initialization is complete + registerChrono(ISOChrono.INSTANCE); + return true; + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Chrono} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code Chrono}. + * If the specified temporal object does not have a chronology, {@link ISOChrono} is returned. + *

    + * The conversion will obtain the chronology using {@link Queries#chrono()}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code Chrono::from}. + * + * @param temporal the temporal to convert, not null + * @return the chronology, not null + * @throws DateTimeException if unable to convert to an {@code Chrono} + */ + public static Chrono from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); + Chrono obj = temporal.query(Queries.chrono()); + return (obj != null ? obj : ISOChrono.INSTANCE); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Chrono} from a locale. + *

    + * The locale can be used to identify a calendar. + * This uses {@link Locale#getUnicodeLocaleType(String)} to obtain the "ca" key + * to identify the calendar system. + *

    + * If the locale does not contain calendar system information, the standard + * ISO calendar system is used. + * + * @param locale the locale to use to obtain the calendar system, not null + * @return the calendar system associated with the locale, not null + * @throws DateTimeException if the locale-specified calendar cannot be found + */ + public static Chrono ofLocale(Locale locale) { + Objects.requireNonNull(locale, "locale"); + String type = locale.getUnicodeLocaleType("ca"); + if (type == null) { + return ISOChrono.INSTANCE; + } else if ("iso".equals(type) || "iso8601".equals(type)) { + return ISOChrono.INSTANCE; + } else { + Chrono chrono = CHRONOS_BY_TYPE.get(type); + if (chrono == null) { + throw new DateTimeException("Unknown calendar system: " + type); + } + return chrono; + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Chrono} from a chronology ID or + * calendar system type. + *

    + * This returns a chronology based on either the ID or the type. + * The {@link #getId() chronology ID} uniquely identifies the chronology. + * The {@link #getCalendarType() calendar system type} is defined by the LDML specification. + *

    + * The chronology may be a system chronology or a chronology + * provided by the application via ServiceLoader configuration. + *

    + * Since some calendars can be customized, the ID or type typically refers + * to the default customization. For example, the Gregorian calendar can have multiple + * cutover dates from the Julian, but the lookup only provides the default cutover date. + * + * @param id the chronology ID or calendar system type, not null + * @return the chronology with the identifier requested, not null + * @throws DateTimeException if the chronology cannot be found + */ + public static Chrono of(String id) { + Objects.requireNonNull(id, "id"); + do { + Chrono chrono = of0(id); + if (chrono != null) { + return chrono; + } + // If not found, do the initialization (once) and repeat the lookup + } while (initCache()); + + // Look for a Chrono using ServiceLoader of the Thread's ContextClassLoader + // Application provided Chronologies must not be cached + @SuppressWarnings("rawtypes") + ServiceLoader loader = ServiceLoader.load(Chrono.class); + for (Chrono chrono : loader) { + if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) { + return chrono; + } + } + throw new DateTimeException("Unknown chronology: " + id); + } + + /** + * Obtains an instance of {@code Chrono} from a chronology ID or + * calendar system type. + * + * @param id the chronology ID or calendar system type, not null + * @return the chronology with the identifier requested, or {@code null} if not found + */ + private static Chrono of0(String id) { + Chrono chrono = CHRONOS_BY_ID.get(id); + if (chrono == null) { + chrono = CHRONOS_BY_TYPE.get(id); + } + return chrono; + } + + /** + * Returns the available chronologies. + *

    + * Each returned {@code Chrono} is available for use in the system. + * The set of chronologies includes the system chronologies and + * any chronologies provided by the application via ServiceLoader + * configuration. + * + * @return the independent, modifiable set of the available chronology IDs, not null + */ + public static Set> getAvailableChronologies() { + initCache(); // force initialization + HashSet> chronos = new HashSet<>(CHRONOS_BY_ID.values()); + + /// Add in Chronologies from the ServiceLoader configuration + @SuppressWarnings("rawtypes") + ServiceLoader loader = ServiceLoader.load(Chrono.class); + for (Chrono chrono : loader) { + chronos.add(chrono); + } + return chronos; + } + + //----------------------------------------------------------------------- + /** + * Obtains a local date-time from the a date and time. + *

    + * This combines a {@link ChronoLocalDate}, which provides the {@code Chrono}, + * with a {@link LocalTime} to produce a {@link ChronoLocalDateTime}. + *

    + * This method is intended for chronology implementations. + * It uses a standard implementation that is shared for all chronologies. + * + * @param the chronology of the date + * @param date the date, not null + * @param time the time, not null + * @return the local date-time combining the input date and time, not null + */ + public static > ChronoLocalDateTime dateTime(ChronoLocalDate date, LocalTime time) { + return ChronoLocalDateTimeImpl.of(date, time); + } + + //----------------------------------------------------------------------- + /** + * Creates an instance. + */ + protected Chrono() { + } + + //----------------------------------------------------------------------- + /** + * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology. + * + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDate}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate + * or the chronology is not equal this Chrono + */ + ChronoLocalDate ensureChronoLocalDate(Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoLocalDate other = (ChronoLocalDate) temporal; + if (this.equals(other.getChrono()) == false) { + throw new ClassCastException("Chrono mismatch, expected: " + getId() + ", actual: " + other.getChrono().getId()); + } + return other; + } + + /** + * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology. + * + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl + * or the chronology is not equal this Chrono + */ + ChronoLocalDateTimeImpl ensureChronoLocalDateTime(Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; + if (this.equals(other.getDate().getChrono()) == false) { + throw new ClassCastException("Chrono mismatch, required: " + getId() + + ", supplied: " + other.getDate().getChrono().getId()); + } + return other; + } + + /** + * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology. + * + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl + * or the chronology is not equal this Chrono + */ + ChronoZonedDateTimeImpl ensureChronoZonedDateTime(Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; + if (this.equals(other.getDate().getChrono()) == false) { + throw new ClassCastException("Chrono mismatch, required: " + getId() + + ", supplied: " + other.getDate().getChrono().getId()); + } + return other; + } + + //----------------------------------------------------------------------- + /** + * Gets the ID of the chronology. + *

    + * The ID uniquely identifies the {@code Chrono}. + * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * + * @return the chronology ID, not null + * @see #getCalendarType() + */ + public abstract String getId(); + + /** + * Gets the calendar type of the underlying calendar system. + *

    + * 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 also be used as part of a locale, accessible via + * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. + * + * @return the calendar system type, null if the calendar is not defined by LDML + * @see #getId() + */ + public abstract String getCalendarType(); + + //----------------------------------------------------------------------- + /** + * Obtains a local date in this chronology from the era, year-of-era, + * month-of-year and day-of-month fields. + * + * @param era the era of the correct type for the chronology, not null + * @param yearOfEra the chronology year-of-era + * @param month the chronology month-of-year + * @param dayOfMonth the chronology day-of-month + * @return the local date in this chronology, not null + * @throws DateTimeException if unable to create the date + */ + public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + return date(prolepticYear(era, yearOfEra), month, dayOfMonth); + } + + /** + * Obtains a local date in this chronology from the proleptic-year, + * month-of-year and day-of-month fields. + * + * @param prolepticYear the chronology proleptic-year + * @param month the chronology month-of-year + * @param dayOfMonth the chronology day-of-month + * @return the local date in this chronology, not null + * @throws DateTimeException if unable to create the date + */ + public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); + + /** + * Obtains a local date in this chronology from the era, year-of-era and + * day-of-year fields. + * + * @param era the era of the correct type for the chronology, not null + * @param yearOfEra the chronology year-of-era + * @param dayOfYear the chronology day-of-year + * @return the local date in this chronology, not null + * @throws DateTimeException if unable to create the date + */ + public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); + } + + /** + * Obtains a local date in this chronology from the proleptic-year and + * day-of-year fields. + * + * @param prolepticYear the chronology proleptic-year + * @param dayOfYear the chronology day-of-year + * @return the local date in this chronology, not null + * @throws DateTimeException if unable to create the date + */ + public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); + + /** + * Obtains a local date in this chronology from another temporal object. + *

    + * This creates a date in this chronology based on the specified {@code TemporalAccessor}. + *

    + * The standard mechanism for conversion between date types is the + * {@link ChronoField#EPOCH_DAY local epoch-day} field. + * + * @param temporal the temporal object to convert, not null + * @return the local date in this chronology, not null + * @throws DateTimeException if unable to create the date + */ + public abstract ChronoLocalDate date(TemporalAccessor temporal); + + //----------------------------------------------------------------------- + /** + * Obtains the current local date in this chronology from the system clock in the default time-zone. + *

    + * This will query the {@link Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + *

    + * This implementation uses {@link #dateNow(Clock)}. + * + * @return the current local date using the system clock and default time-zone, not null + * @throws DateTimeException if unable to create the date + */ + public ChronoLocalDate dateNow() { + return dateNow(Clock.systemDefaultZone()); + } + + /** + * Obtains the current local date in this chronology from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. + * Specifying the time-zone avoids dependence on the default time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current local date using the system clock, not null + * @throws DateTimeException if unable to create the date + */ + public ChronoLocalDate dateNow(ZoneId zone) { + return dateNow(Clock.system(zone)); + } + + /** + * Obtains the current local date in this chronology from the specified clock. + *

    + * This will query the specified clock to obtain the current date - today. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current local date, not null + * @throws DateTimeException if unable to create the date + */ + public ChronoLocalDate dateNow(Clock clock) { + Objects.requireNonNull(clock, "clock"); + return date(LocalDate.now(clock)); + } + + //----------------------------------------------------------------------- + /** + * Obtains a local date-time in this chronology from another temporal object. + *

    + * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}. + *

    + * The date of the date-time should be equivalent to that obtained by calling + * {@link #date(TemporalAccessor)}. + * The standard mechanism for conversion between time types is the + * {@link ChronoField#NANO_OF_DAY nano-of-day} field. + * + * @param temporal the temporal object to convert, not null + * @return the local date-time in this chronology, not null + * @throws DateTimeException if unable to create the date-time + */ + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + try { + return date(temporal).atTime(LocalTime.from(temporal)); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + /** + * Obtains a zoned date-time in this chronology from another temporal object. + *

    + * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}. + *

    + * This should obtain a {@code ZoneId} using {@link ZoneId#from(TemporalAccessor)}. + * The date-time should be obtained by obtaining an {@code Instant}. + * If that fails, the local date-time should be used. + * + * @param temporal the temporal object to convert, not null + * @return the zoned date-time in this chronology, not null + * @throws DateTimeException if unable to create the date-time + */ + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + try { + ZoneId zone = ZoneId.from(temporal); + try { + Instant instant = Instant.from(temporal); + return zonedDateTime(instant, zone); + + } catch (DateTimeException ex1) { + ChronoLocalDateTimeImpl cldt = ensureChronoLocalDateTime(localDateTime(temporal)); + return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null); + } + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + /** + * Obtains a zoned date-time in this chronology from an {@code Instant}. + *

    + * This creates a zoned date-time with the same instant as that specified. + * + * @param instant the instant to create the date-time from, not null + * @param zone the time-zone, not null + * @return the zoned date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified year is a leap year. + *

    + * A leap-year is a year of a longer length than normal. + * The exact meaning is determined by the chronology according to the following constraints. + *

      + *
    • a leap-year must imply a year-length longer than a non leap-year. + *
    • a chronology that does not support the concept of a year must return false. + *

    + * + * @param prolepticYear the proleptic-year to check, not validated for range + * @return true if the year is a leap year + */ + public abstract boolean isLeapYear(long prolepticYear); + + /** + * Calculates the proleptic-year given the era and year-of-era. + *

    + * This combines the era and year-of-era into the single proleptic-year field. + * + * @param era the era of the correct type for the chronology, not null + * @param yearOfEra the chronology year-of-era + * @return the proleptic-year + * @throws DateTimeException if unable to convert + */ + public abstract int prolepticYear(Era era, int yearOfEra); + + /** + * Creates the chronology era object from the numeric value. + *

    + * The era is, conceptually, the largest division of the time-line. + * Most calendar systems have a single epoch dividing the time-line into two eras. + * However, some have multiple eras, such as one for the reign of each leader. + * The exact meaning is determined by the chronology according to the following constraints. + *

    + * The era in use at 1970-01-01 must have the value 1. + * Later eras must have sequentially higher values. + * Earlier eras must have sequentially lower values. + * Each chronology must refer to an enum or similar singleton to provide the era values. + *

    + * This method returns the singleton era of the correct type for the specified era value. + * + * @param eraValue the era value + * @return the calendar system era, not null + * @throws DateTimeException if unable to create the era + */ + public abstract Era eraOf(int eraValue); + + /** + * Gets the list of eras for the chronology. + *

    + * Most calendar systems have an era, within which the year has meaning. + * If the calendar system does not support the concept of eras, an empty + * list must be returned. + * + * @return the list of eras for the chronology, may be immutable, not null + */ + public abstract List> eras(); + + //----------------------------------------------------------------------- + /** + * Gets the range of valid values for the specified field. + *

    + * All fields can be expressed as a {@code long} integer. + * This method returns an object that describes the valid range for that value. + *

    + * Note that the result only describes the minimum and maximum valid values + * and it is important not to read too much into them. For example, there + * could be values within the range that are invalid for the field. + *

    + * This method will return a result whether or not the chronology supports the field. + * + * @param field the field to get the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + public abstract ValueRange range(ChronoField field); + + //----------------------------------------------------------------------- + /** + * Gets the textual representation of this chronology. + *

    + * This returns the textual name used to identify the chronology. + * The parameters control the style of the returned text and the locale. + * + * @param style the style of the text required, not null + * @param locale the locale to use, not null + * @return the text value of the chronology, not null + */ + public String getText(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendChronoText(style).toFormatter(locale).print(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return false; + } + @Override + public long getLong(TemporalField field) { + throw new DateTimeException("Unsupported field: " + field); + } + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) Chrono.this; + } + return TemporalAccessor.super.query(query); + } + }); + } + + //----------------------------------------------------------------------- + /** + * Compares this chronology to another chronology. + *

    + * The comparison order first by the chronology ID string, then by any + * additional information specific to the subclass. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * The default implementation compares the chronology ID. + * Subclasses must compare any additional state that they store. + * + * @param other the other chronology to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(Chrono other) { + return getId().compareTo(other.getId()); + } + + /** + * Checks if this chronology is equal to another chronology. + *

    + * The comparison is based on the entire state of the object. + *

    + * The default implementation checks the type and calls {@link #compareTo(Chrono)}. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other chronology + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Chrono) { + return compareTo((Chrono) obj) == 0; + } + return false; + } + + /** + * A hash code for this chronology. + *

    + * The default implementation is based on the ID and class. + * Subclasses should add any additional state that they store. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return getClass().hashCode() ^ getId().hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Outputs this chronology as a {@code String}, using the ID. + * + * @return a string representation of this chronology, not null + */ + @Override + public String toString() { + return getId(); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(7);  // identifies this as a Chrono
    +     * out.writeUTF(chronoId);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.CHRONO_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeUTF(getId()); + } + + static Chrono readExternal(DataInput in) throws IOException { + String id = in.readUTF(); + return Chrono.of(id); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoField.java b/jdk/src/share/classes/java/time/temporal/ChronoField.java new file mode 100644 index 00000000000..f163654225b --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoField.java @@ -0,0 +1,610 @@ +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.FOREVER; +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.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeBuilder; + +/** + * A standard set of fields. + *

    + * This set of fields provide field-based access to manipulate a date, time or date-time. + * The standard set of fields can be extended by implementing {@link TemporalField}. + *

    + * These fields are intended to be applicable in multiple calendar systems. + * For example, most non-ISO calendar systems define dates as a year, month and day, + * just with slightly different rules. + * The documentation of each field explains how it operates. + * + *

    Specification for implementors

    + * This is a final, immutable and thread-safe enum. + * + * @since 1.8 + */ +public enum ChronoField implements TemporalField { + + /** + * The nano-of-second. + *

    + * This counts the nanosecond within the second, from 0 to 999,999,999. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the nano-of-second handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or + * {@link #INSTANT_SECONDS} filling unknown precision with zero. + *

    + * When this field is used for setting a value, it should set as much precision as the + * object stores, using integer division to remove excess precision. + * For example, if the {@code TemporalAccessor} stores time to millisecond precision, + * then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second. + */ + NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)), + /** + * The nano-of-day. + *

    + * This counts the nanosecond within the day, from 0 to (24 * 60 * 60 * 1,000,000,000) - 1. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the nano-of-day handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero. + */ + NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)), + /** + * The micro-of-second. + *

    + * This counts the microsecond within the second, from 0 to 999,999. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the micro-of-second handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or + * {@link #INSTANT_SECONDS} filling unknown precision with zero. + *

    + * When this field is used for setting a value, it should behave in the same way as + * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000. + */ + MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)), + /** + * The micro-of-day. + *

    + * This counts the microsecond within the day, from 0 to (24 * 60 * 60 * 1,000,000) - 1. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the micro-of-day handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero. + *

    + * When this field is used for setting a value, it should behave in the same way as + * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000. + */ + MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)), + /** + * The milli-of-second. + *

    + * This counts the millisecond within the second, from 0 to 999. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the milli-of-second handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or + * {@link #INSTANT_SECONDS} filling unknown precision with zero. + *

    + * When this field is used for setting a value, it should behave in the same way as + * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000. + */ + MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)), + /** + * The milli-of-day. + *

    + * This counts the millisecond within the day, from 0 to (24 * 60 * 60 * 1,000) - 1. + * This field has the same meaning for all calendar systems. + *

    + * This field is used to represent the milli-of-day handling any fraction of the second. + * Implementations of {@code TemporalAccessor} should provide a value for this field if + * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero. + *

    + * When this field is used for setting a value, it should behave in the same way as + * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000. + */ + MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)), + /** + * The second-of-minute. + *

    + * This counts the second within the minute, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59)), + /** + * The second-of-day. + *

    + * This counts the second within the day, from 0 to (24 * 60 * 60) - 1. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)), + /** + * The minute-of-hour. + *

    + * This counts the minute within the hour, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59)), + /** + * The minute-of-day. + *

    + * This counts the minute within the day, from 0 to (24 * 60) - 1. + * This field has the same meaning for all calendar systems. + */ + MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)), + /** + * The hour-of-am-pm. + *

    + * This counts the hour within the AM/PM, from 0 to 11. + * This is the hour that would be observed on a standard 12-hour digital clock. + * This field has the same meaning for all calendar systems. + */ + HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)), + /** + * The clock-hour-of-am-pm. + *

    + * This counts the hour within the AM/PM, from 1 to 12. + * This is the hour that would be observed on a standard 12-hour analog wall clock. + * This field has the same meaning for all calendar systems. + */ + CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)), + /** + * The hour-of-day. + *

    + * This counts the hour within the day, from 0 to 23. + * This is the hour that would be observed on a standard 24-hour digital clock. + * This field has the same meaning for all calendar systems. + */ + HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23)), + /** + * The clock-hour-of-day. + *

    + * This counts the hour within the AM/PM, from 1 to 24. + * This is the hour that would be observed on a 24-hour analog wall clock. + * This field has the same meaning for all calendar systems. + */ + CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)), + /** + * The am-pm-of-day. + *

    + * This counts the AM/PM within the day, from 0 (AM) to 1 (PM). + * This field has the same meaning for all calendar systems. + */ + AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1)), + /** + * The day-of-week, such as Tuesday. + *

    + * This represents the standard concept of the day of the week. + * In the default ISO calendar system, this has values from Monday (1) to Sunday (7). + * The {@link DayOfWeek} class can be used to interpret the result. + *

    + * Most non-ISO calendar systems also define a seven day week that aligns with ISO. + * Those calendar systems must also use the same numbering system, from Monday (1) to + * Sunday (7), which allows {@code DayOfWeek} to be used. + *

    + * Calendar systems that do not have a standard seven day week should implement this field + * if they have a similar concept of named or numbered days within a period similar + * to a week. It is recommended that the numbering starts from 1. + */ + DAY_OF_WEEK("DayOfWeek", DAYS, WEEKS, ValueRange.of(1, 7)), + /** + * The aligned day-of-week within a month. + *

    + * This represents concept of the count of days within the period of a week + * where the weeks are aligned to the start of the month. + * This field is typically used with {@link #ALIGNED_WEEK_OF_MONTH}. + *

    + * For example, in a calendar systems with a seven day week, the first aligned-week-of-month + * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on. + * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned + * as the value of this field. + * As such, day-of-month 1 to 7 will have aligned-day-of-week values from 1 to 7. + * And day-of-month 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7. + *

    + * Calendar systems that do not have a seven day week should typically implement this + * field in the same way, but using the alternate week length. + */ + ALIGNED_DAY_OF_WEEK_IN_MONTH("AlignedDayOfWeekInMonth", DAYS, WEEKS, ValueRange.of(1, 7)), + /** + * The aligned day-of-week within a year. + *

    + * This represents concept of the count of days within the period of a week + * where the weeks are aligned to the start of the year. + * This field is typically used with {@link #ALIGNED_WEEK_OF_YEAR}. + *

    + * For example, in a calendar systems with a seven day week, the first aligned-week-of-year + * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on. + * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned + * as the value of this field. + * As such, day-of-year 1 to 7 will have aligned-day-of-week values from 1 to 7. + * And day-of-year 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7. + *

    + * Calendar systems that do not have a seven day week should typically implement this + * field in the same way, but using the alternate week length. + */ + ALIGNED_DAY_OF_WEEK_IN_YEAR("AlignedDayOfWeekInYear", DAYS, WEEKS, ValueRange.of(1, 7)), + /** + * The day-of-month. + *

    + * This represents the concept of the day within the month. + * In the default ISO calendar system, this has values from 1 to 31 in most months. + * April, June, September, November have days from 1 to 30, while February has days + * from 1 to 28, or 29 in a leap year. + *

    + * Non-ISO calendar systems should implement this field using the most recognized + * day-of-month values for users of the calendar system. + * Normally, this is a count of days from 1 to the length of the month. + */ + DAY_OF_MONTH("DayOfMonth", DAYS, MONTHS, ValueRange.of(1, 28, 31)), + /** + * The day-of-year. + *

    + * This represents the concept of the day within the year. + * In the default ISO calendar system, this has values from 1 to 365 in standard + * years and 1 to 366 in leap years. + *

    + * Non-ISO calendar systems should implement this field using the most recognized + * day-of-year values for users of the calendar system. + * Normally, this is a count of days from 1 to the length of the year. + */ + DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)), + /** + * The epoch-day, based on the Java epoch of 1970-01-01 (ISO). + *

    + * This field is the sequential count of days where 1970-01-01 (ISO) is zero. + * Note that this uses the local time-line, ignoring offset and time-zone. + *

    + * This field is strictly defined to have the same meaning in all calendar systems. + * This is necessary to ensure interoperation between calendars. + */ + EPOCH_DAY("EpochDay", DAYS, FOREVER, ValueRange.of((long) (Year.MIN_VALUE * 365.25), (long) (Year.MAX_VALUE * 365.25))), + /** + * The aligned week within a month. + *

    + * This represents concept of the count of weeks within the period of a month + * where the weeks are aligned to the start of the month. + * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_MONTH}. + *

    + * For example, in a calendar systems with a seven day week, the first aligned-week-of-month + * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on. + * Thus, day-of-month values 1 to 7 are in aligned-week 1, while day-of-month values + * 8 to 14 are in aligned-week 2, and so on. + *

    + * Calendar systems that do not have a seven day week should typically implement this + * field in the same way, but using the alternate week length. + */ + ALIGNED_WEEK_OF_MONTH("AlignedWeekOfMonth", WEEKS, MONTHS, ValueRange.of(1, 4, 5)), + /** + * The aligned week within a year. + *

    + * This represents concept of the count of weeks within the period of a year + * where the weeks are aligned to the start of the year. + * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_YEAR}. + *

    + * For example, in a calendar systems with a seven day week, the first aligned-week-of-year + * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on. + * Thus, day-of-year values 1 to 7 are in aligned-week 1, while day-of-year values + * 8 to 14 are in aligned-week 2, and so on. + *

    + * Calendar systems that do not have a seven day week should typically implement this + * field in the same way, but using the alternate week length. + */ + ALIGNED_WEEK_OF_YEAR("AlignedWeekOfYear", WEEKS, YEARS, ValueRange.of(1, 53)), + /** + * The month-of-year, such as March. + *

    + * This represents the concept of the month within the year. + * In the default ISO calendar system, this has values from January (1) to December (12). + *

    + * Non-ISO calendar systems should implement this field using the most recognized + * month-of-year values for users of the calendar system. + * Normally, this is a count of months starting from 1. + */ + MONTH_OF_YEAR("MonthOfYear", MONTHS, YEARS, ValueRange.of(1, 12)), + /** + * The epoch-month based on the Java epoch of 1970-01-01. + *

    + * This field is the sequential count of months where January 1970 (ISO) is zero. + * Note that this uses the local time-line, ignoring offset and time-zone. + *

    + * Non-ISO calendar systems should also implement this field to represent a sequential + * count of months. It is recommended to define zero as the month of 1970-01-01 (ISO). + */ + EPOCH_MONTH("EpochMonth", MONTHS, FOREVER, ValueRange.of((Year.MIN_VALUE - 1970L) * 12, (Year.MAX_VALUE - 1970L) * 12L - 1L)), + /** + * The year within the era. + *

    + * This represents the concept of the year within the era. + * This field is typically used with {@link #ERA}. + *

    + * The standard mental model for a date is based on three concepts - year, month and day. + * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Note that there is no reference to eras. + * The full model for a date requires four concepts - era, year, month and day. These map onto + * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Whether this field or {@code YEAR} is used depends on which mental model is being used. + * See {@link ChronoLocalDate} for more discussion on this topic. + *

    + * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'. + * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value. + * The era 'BCE' is the previous era, and the year-of-era runs backwards. + *

    + * For example, subtracting a year each time yield the following:
    + * - year-proleptic 2 = 'CE' year-of-era 2
    + * - year-proleptic 1 = 'CE' year-of-era 1
    + * - year-proleptic 0 = 'BCE' year-of-era 1
    + * - year-proleptic -1 = 'BCE' year-of-era 2
    + *

    + * Note that the ISO-8601 standard does not actually define eras. + * Note also that the ISO eras do not align with the well-known AD/BC eras due to the + * change between the Julian and Gregorian calendar systems. + *

    + * Non-ISO calendar systems should implement this field using the most recognized + * year-of-era value for users of the calendar system. + * Since most calendar systems have only two eras, the year-of-era numbering approach + * will typically be the same as that used by the ISO calendar system. + * The year-of-era value should typically always be positive, however this is not required. + */ + YEAR_OF_ERA("YearOfEra", YEARS, FOREVER, ValueRange.of(1, Year.MAX_VALUE, Year.MAX_VALUE + 1)), + /** + * The proleptic year, such as 2012. + *

    + * This represents the concept of the year, counting sequentially and using negative numbers. + * The proleptic year is not interpreted in terms of the era. + * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era. + *

    + * The standard mental model for a date is based on three concepts - year, month and day. + * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Note that there is no reference to eras. + * The full model for a date requires four concepts - era, year, month and day. These map onto + * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used. + * See {@link ChronoLocalDate} for more discussion on this topic. + *

    + * Non-ISO calendar systems should implement this field as follows. + * If the calendar system has only two eras, before and after a fixed date, then the + * proleptic-year value must be the same as the year-of-era value for the later era, + * and increasingly negative for the earlier era. + * If the calendar system has more than two eras, then the proleptic-year value may be + * defined with any appropriate value, although defining it to be the same as ISO may be + * the best option. + */ + YEAR("Year", YEARS, FOREVER, ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE)), + /** + * The era. + *

    + * This represents the concept of the era, which is the largest division of the time-line. + * This field is typically used with {@link #YEAR_OF_ERA}. + *

    + * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'. + * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value. + * The era 'BCE' is the previous era, and the year-of-era runs backwards. + * See {@link #YEAR_OF_ERA} for a full example. + *

    + * Non-ISO calendar systems should implement this field to define eras. + * The value of the era that was active on 1970-01-01 (ISO) must be assigned the value 1. + * Earlier eras must have sequentially smaller values. + * Later eras must have sequentially larger values, + */ + ERA("Era", ERAS, FOREVER, ValueRange.of(0, 1)), + /** + * The instant epoch-seconds. + *

    + * This represents the concept of the sequential count of seconds where + * 1970-01-01T00:00Z (ISO) is zero. + * This field may be used with {@link #NANO_OF_DAY} to represent the fraction of the day. + *

    + * An {@link Instant} represents an instantaneous point on the time-line. + * On their own they have no elements which allow a local date-time to be obtained. + * Only when paired with an offset or time-zone can the local date or time be found. + * This field allows the seconds part of the instant to be queried. + *

    + * This field is strictly defined to have the same meaning in all calendar systems. + * This is necessary to ensure interoperation between calendars. + */ + INSTANT_SECONDS("InstantSeconds", SECONDS, FOREVER, ValueRange.of(Long.MIN_VALUE, Long.MAX_VALUE)), + /** + * The offset from UTC/Greenwich. + *

    + * This represents the concept of the offset in seconds of local time from UTC/Greenwich. + *

    + * A {@link ZoneOffset} represents the period of time that local time differs from UTC/Greenwich. + * This is usually a fixed number of hours and minutes. + * It is equivalent to the {@link ZoneOffset#getTotalSeconds() total amount} of the offset in seconds. + * For example, during the winter Paris has an offset of {@code +01:00}, which is 3600 seconds. + *

    + * This field is strictly defined to have the same meaning in all calendar systems. + * This is necessary to ensure interoperation between calendars. + */ + OFFSET_SECONDS("OffsetSeconds", SECONDS, FOREVER, ValueRange.of(-18 * 3600, 18 * 3600)); + + private final String name; + private final TemporalUnit baseUnit; + private final TemporalUnit rangeUnit; + private final ValueRange range; + + private ChronoField(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) { + this.name = name; + this.baseUnit = baseUnit; + this.rangeUnit = rangeUnit; + this.range = range; + } + + //----------------------------------------------------------------------- + @Override + public String getName() { + return name; + } + + @Override + public TemporalUnit getBaseUnit() { + return baseUnit; + } + + @Override + public TemporalUnit getRangeUnit() { + return rangeUnit; + } + + @Override + public ValueRange range() { + return range; + } + + //----------------------------------------------------------------------- + /** + * Checks if this field represents a component of a date. + * + * @return true if it is a component of a date + */ + public boolean isDateField() { + return ordinal() >= DAY_OF_WEEK.ordinal() && ordinal() <= ERA.ordinal(); + } + + /** + * Checks if this field represents a component of a time. + * + * @return true if it is a component of a time + */ + public boolean isTimeField() { + return ordinal() < DAY_OF_WEEK.ordinal(); + } + + //----------------------------------------------------------------------- + /** + * Checks that the specified value is valid for this field. + *

    + * This validates that the value is within the outer range of valid values + * returned by {@link #range()}. + * + * @param value the value to check + * @return the value that was passed in + */ + public long checkValidValue(long value) { + return range().checkValidValue(value, this); + } + + /** + * Checks that the specified value is valid and fits in an {@code int}. + *

    + * This validates that the value is within the outer range of valid values + * returned by {@link #range()}. + * It also checks that all valid values are within the bounds of an {@code int}. + * + * @param value the value to check + * @return the value that was passed in + */ + public int checkValidIntValue(long value) { + return range().checkValidIntValue(value, this); + } + + //----------------------------------------------------------------------- + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(this); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + return temporal.range(this); + } + + @Override + public long doGet(TemporalAccessor temporal) { + return temporal.getLong(this); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(R temporal, long newValue) { + return (R) temporal.with(this, newValue); + } + + //----------------------------------------------------------------------- + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + return false; // resolve implemented in builder + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + return getName(); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java b/jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java new file mode 100644 index 00000000000..4701296bd7a --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java @@ -0,0 +1,691 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoUnit.DAYS; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Comparator; +import java.util.Objects; + +/** + * A date without time-of-day or time-zone in an arbitrary chronology, intended + * for advanced globalization use cases. + *

    + * Most applications should declare method signatures, fields and variables + * as {@link LocalDate}, not this interface. + *

    + * A {@code ChronoLocalDate} is the abstract representation of a date where the + * {@code Chrono chronology}, or calendar system, is pluggable. + * The date is defined in terms of fields expressed by {@link TemporalField}, + * where most common implementations are defined in {@link ChronoField}. + * The chronology defines how the calendar system operates and the meaning of + * the standard fields. + * + *

    When to use this interface

    + * The design of the API encourages the use of {@code LocalDate} rather than this + * interface, even in the case where the application needs to deal with multiple + * calendar systems. The rationale for this is explored in the following documentation. + *

    + * The primary use case where this interface should be used is where the generic + * type parameter {@code } is fully defined as a specific chronology. + * In that case, the assumptions of that chronology are known at development + * time and specified in the code. + *

    + * When the chronology is defined in the generic type parameter as ? or otherwise + * unknown at development time, the rest of the discussion below applies. + *

    + * To emphasize the point, declaring a method signature, field or variable as this + * interface type can initially seem like the sensible way to globalize an application, + * however it is usually the wrong approach. + * As such, it should be considered an application-wide architectural decision to choose + * to use this interface as opposed to {@code LocalDate}. + * + *

    Architectural issues to consider

    + * These are some of the points that must be considered before using this interface + * throughout an application. + *

    + * 1) Applications using this interface, as opposed to using just {@code LocalDate}, + * face a significantly higher probability of bugs. This is because the calendar system + * in use is not known at development time. A key cause of bugs is where the developer + * applies assumptions from their day-to-day knowledge of the ISO calendar system + * to code that is intended to deal with any arbitrary calendar system. + * The section below outlines how those assumptions can cause problems + * The primary mechanism for reducing this increased risk of bugs is a strong code review process. + * This should also be considered a extra cost in maintenance for the lifetime of the code. + *

    + * 2) This interface does not enforce immutability of implementations. + * While the implementation notes indicate that all implementations must be immutable + * there is nothing in the code or type system to enforce this. Any method declared + * to accept a {@code ChronoLocalDate} could therefore be passed a poorly or + * maliciously written mutable implementation. + *

    + * 3) Applications using this interface must consider the impact of eras. + * {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()} + * returns the proleptic year. That decision ensures that developers can think of + * {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month. + * By contrast, users of this interface must think of dates as consisting of four fields - + * era, year-of-era, month-of-year and day-of-month. The extra era field is frequently + * forgotten, yet it is of vital importance to dates in an arbitrary calendar system. + * For example, in the Japanese calendar system, the era represents the reign of an Emperor. + * Whenever one reign ends and another starts, the year-of-era is reset to one. + *

    + * 4) The only agreed international standard for passing a date between two systems + * is the ISO-8601 standard which requires the ISO calendar system. Using this interface + * throughout the application will inevitably lead to the requirement to pass the date + * across a network or component boundary, requiring an application specific protocol or format. + *

    + * 5) Long term persistence, such as a database, will almost always only accept dates in the + * ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other + * calendar systems increases the complications of interacting with persistence. + *

    + * 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application + * is unnecessary, as discussed in the last section below. + * + *

    False assumptions causing bugs in multi-calendar system code

    + * As indicated above, there are many issues to consider when try to use and manipulate a + * date in an arbitrary calendar system. These are some of the key issues. + *

    + * Code that queries the day-of-month and assumes that the value will never be more than + * 31 is invalid. Some calendar systems have more than 31 days in some months. + *

    + * Code that adds 12 months to a date and assumes that a year has been added is invalid. + * Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic. + *

    + * Code that adds one month to a date and assumes that the month-of-year value will increase + * by one or wrap to the next year is invalid. Some calendar systems have a variable number + * of months in a year, such as the Hebrew. + *

    + * Code that adds one month, then adds a second one month and assumes that the day-of-month + * will remain close to its original value is invalid. Some calendar systems have a large difference + * between the length of the longest month and the length of the shortest month. + * For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days. + *

    + * Code that adds seven days and assumes that a week has been added is invalid. + * Some calendar systems have weeks of other than seven days, such as the French Revolutionary. + *

    + * Code that assumes that because the year of {@code date1} is greater than the year of {@code date2} + * then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems + * when referring to the year-of-era, and especially untrue of the Japanese calendar system + * where the year-of-era restarts with the reign of every new Emperor. + *

    + * Code that treats month-of-year one and day-of-month one as the start of the year is invalid. + * Not all calendar systems start the year when the month value is one. + *

    + * In general, manipulating a date, and even querying a date, is wide open to bugs when the + * calendar system is unknown at development time. This is why it is essential that code using + * this interface is subjected to additional code reviews. It is also why an architectural + * decision to avoid this interface type is usually the correct one. + * + *

    Using LocalDate instead

    + * The primary alternative to using this interface throughout your application is as follows. + *

      + *
    • Declare all method signatures referring to dates in terms of {@code LocalDate}. + *
    • Either store the chronology (calendar system) in the user profile or lookup + * the chronology from the user locale + *
    • Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during + * printing and parsing + *

    + * This approach treats the problem of globalized calendar systems as a localization issue + * and confines it to the UI layer. This approach is in keeping with other localization + * issues in the java platform. + *

    + * As discussed above, performing calculations on a date where the rules of the calendar system + * are pluggable requires skill and is not recommended. + * Fortunately, the need to perform calculations on a date in an arbitrary calendar system + * is extremely rare. For example, it is highly unlikely that the business rules of a library + * book rental scheme will allow rentals to be for one month, where meaning of the month + * is dependent on the user's preferred calendar system. + *

    + * A key use case for calculations on a date in an arbitrary calendar system is producing + * a month-by-month calendar for display and user interaction. Again, this is a UI issue, + * and use of this interface solely within a few methods of the UI layer may be justified. + *

    + * In any other part of the system, where a date must be manipulated in a calendar system + * other than ISO, the use case will generally specify the calendar system to use. + * For example, an application may need to calculate the next Islamic or Hebrew holiday + * which may require manipulating the date. + * This kind of use case can be handled as follows: + *

      + *
    • start from the ISO {@code LocalDate} being passed to the method + *
    • convert the date to the alternate calendar system, which for this use case is known + * rather than arbitrary + *
    • perform the calculation + *
    • convert back to {@code LocalDate} + *

    + * Developers writing low-level frameworks or libraries should also avoid this interface. + * Instead, one of the two general purpose access interfaces should be used. + * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal} + * if read-write access is required. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + *

    + * Additional calendar systems may be added to the system. + * See {@link Chrono} for more details. + * + * @param the chronology of this date + * @since 1.8 + */ +public interface ChronoLocalDate> + extends Temporal, TemporalAdjuster, Comparable> { + + /** + * Comparator for two {@code ChronoLocalDate}s ignoring the chronology. + *

    + * This comparator differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * This is equivalent to using {@code Long.compare(date1.toEpochDay(), date2.toEpochDay())}. + * + * @see #isAfter + * @see #isBefore + * @see #isEqual + */ + public static final Comparator> DATE_COMPARATOR = + new Comparator>() { + @Override + public int compare(ChronoLocalDate date1, ChronoLocalDate date2) { + return Long.compare(date1.toEpochDay(), date2.toEpochDay()); + } + }; + + //----------------------------------------------------------------------- + /** + * Gets the chronology of this date. + *

    + * The {@code Chrono} represents the calendar system in use. + * The era and other fields in {@link ChronoField} are defined by the chronology. + * + * @return the chronology, not null + */ + C getChrono(); + + /** + * Gets the era, as defined by the chronology. + *

    + * The era is, conceptually, the largest division of the time-line. + * Most calendar systems have a single epoch dividing the time-line into two eras. + * However, some have multiple eras, such as one for the reign of each leader. + * The exact meaning is determined by the {@code Chrono}. + *

    + * All correctly implemented {@code Era} classes are singletons, thus it + * is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}. + *

    + * This default implementation uses {@link Chrono#eraOf(int)}. + * + * @return the chronology specific era constant applicable at this date, not null + */ + public default Era getEra() { + return getChrono().eraOf(get(ERA)); + } + + /** + * Checks if the year is a leap year, as defined by the calendar system. + *

    + * A leap-year is a year of a longer length than normal. + * The exact meaning is determined by the chronology with the constraint that + * a leap-year must imply a year-length longer than a non leap-year. + *

    + * This default implementation uses {@link Chrono#isLeapYear(long)}. + * + * @return true if this date is in a leap year, false otherwise + */ + public default boolean isLeapYear() { + return getChrono().isLeapYear(getLong(YEAR)); + } + + /** + * Returns the length of the month represented by this date, as defined by the calendar system. + *

    + * This returns the length of the month in days. + * + * @return the length of the month in days + */ + int lengthOfMonth(); + + /** + * Returns the length of the year represented by this date, as defined by the calendar system. + *

    + * This returns the length of the year in days. + *

    + * The default implementation uses {@link #isLeapYear()} and returns 365 or 366. + * + * @return the length of the year in days + */ + public default int lengthOfYear() { + return (isLeapYear() ? 366 : 365); + } + + @Override + public default boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return ((ChronoField) field).isDateField(); + } + return field != null && field.doIsSupported(this); + } + + //----------------------------------------------------------------------- + // override for covariant return type + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate with(TemporalAdjuster adjuster) { + return getChrono().ensureChronoLocalDate(Temporal.super.with(adjuster)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return getChrono().ensureChronoLocalDate(field.doWith(this, newValue)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate plus(TemporalAdder adder) { + return getChrono().ensureChronoLocalDate(Temporal.super.plus(adder)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return getChrono().ensureChronoLocalDate(unit.doPlus(this, amountToAdd)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate minus(TemporalSubtractor subtractor) { + return getChrono().ensureChronoLocalDate(Temporal.super.minus(subtractor)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { + return getChrono().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Queries this date using the specified query. + *

    + * This queries this date using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public default R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) getChrono(); + } + if (query == Queries.precision()) { + return (R) DAYS; + } + // inline TemporalAccessor.super.query(query) as an optimization + if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { + return null; + } + return query.queryFrom(this); + } + + /** + * Adjusts the specified temporal object to have the same date as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the date changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link ChronoField#EPOCH_DAY} as the field. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisLocalDate.adjustInto(temporal);
    +     *   temporal = temporal.with(thisLocalDate);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public default Temporal adjustInto(Temporal temporal) { + return temporal.with(EPOCH_DAY, toEpochDay()); + } + + /** + * Calculates the period between this date and another date in + * terms of the specified unit. + *

    + * This calculates the period between two dates in terms of a single unit. + * The start and end points are {@code this} and the specified date. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method must be a + * {@code ChronoLocalDate} in the same chronology. + * The calculation returns a whole number, representing the number of + * complete units between the two dates. + * For example, the period in days between two dates can be calculated + * using {@code startDate.periodUntil(endDate, DAYS)}. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, MONTHS);   // this method
    +     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS}, + * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} + * should be supported by all implementations. + * Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endDate the end date, which must be a {@code ChronoLocalDate} + * in the same chronology, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this date and the end date + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public abstract long periodUntil(Temporal endDate, TemporalUnit unit); + + //----------------------------------------------------------------------- + /** + * Returns a date-time formed from this date at the specified time. + *

    + * This merges the two objects - {@code this} and the specified time - + * to form an instance of {@code ChronoLocalDateTime}. + *

    + * This instance is immutable and unaffected by this method call. + *

    + * This default implementation creates the date-time. + * + * @param localTime the local time to use, not null + * @return the local date-time formed from this date and the specified time, not null + */ + public default ChronoLocalDateTime atTime(LocalTime localTime) { + return Chrono.dateTime(this, localTime); + } + + //----------------------------------------------------------------------- + /** + * Converts this date to the Epoch Day. + *

    + * The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple + * incrementing count of days where day 0 is 1970-01-01 (ISO). + * This definition is the same for all chronologies, enabling conversion. + *

    + * This default implementation queries the {@code EPOCH_DAY} field. + * + * @return the Epoch Day equivalent to this date + */ + public default long toEpochDay() { + return getLong(EPOCH_DAY); + } + + //----------------------------------------------------------------------- + /** + * Compares this date to another date, including the chronology. + *

    + * The comparison is based first on the underlying time-line date, then + * on the chronology. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * For example, the following is the comparator order: + *

      + *
    1. {@code 2012-12-03 (ISO)}
    2. + *
    3. {@code 2012-12-04 (ISO)}
    4. + *
    5. {@code 2555-12-04 (ThaiBuddhist)}
    6. + *
    7. {@code 2012-12-05 (ISO)}
    8. + *
    + * Values #2 and #3 represent the same date on the time-line. + * When two values represent the same date, the chronology ID is compared to distinguish them. + * This step is needed to make the ordering "consistent with equals". + *

    + * If all the date objects being compared are in the same chronology, then the + * additional chronology stage is not required and only the local date is used. + * To compare the dates of two {@code TemporalAccessor} instances, including dates + * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. + *

    + * This default implementation performs the comparison defined above. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public default int compareTo(ChronoLocalDate other) { + int cmp = Long.compare(toEpochDay(), other.toEpochDay()); + if (cmp == 0) { + cmp = getChrono().compareTo(other.getChrono()); + } + return cmp; + } + + /** + * Checks if this date is after the specified date ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}. + *

    + * This default implementation performs the comparison based on the epoch-day. + * + * @param other the other date to compare to, not null + * @return true if this is after the specified date + */ + public default boolean isAfter(ChronoLocalDate other) { + return this.toEpochDay() > other.toEpochDay(); + } + + /** + * Checks if this date is before the specified date ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}. + *

    + * This default implementation performs the comparison based on the epoch-day. + * + * @param other the other date to compare to, not null + * @return true if this is before the specified date + */ + public default boolean isBefore(ChronoLocalDate other) { + return this.toEpochDay() < other.toEpochDay(); + } + + /** + * Checks if this date is equal to the specified date ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}. + *

    + * This default implementation performs the comparison based on the epoch-day. + * + * @param other the other date to compare to, not null + * @return true if the underlying date is equal to the specified date + */ + public default boolean isEqual(ChronoLocalDate other) { + return this.toEpochDay() == other.toEpochDay(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this date is equal to another date, including the chronology. + *

    + * Compares this date with another ensuring that the date and chronology are the same. + *

    + * To compare the dates of two {@code TemporalAccessor} instances, including dates + * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + boolean equals(Object obj); + + /** + * A hash code for this date. + * + * @return a suitable hash code + */ + @Override + int hashCode(); + + //----------------------------------------------------------------------- + /** + * Outputs this date as a {@code String}. + *

    + * The output will include the full local date and the chronology ID. + * + * @return the formatted date, not null + */ + @Override + String toString(); + + /** + * Outputs this date as a {@code String} using the formatter. + *

    + * The default implementation must behave as follows: + *

    +     *  return formatter.print(this);
    +     * 
    + * + * @param formatter the formatter to use, not null + * @return the formatted date string, not null + * @throws DateTimeException if an error occurs during printing + */ + public default String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java new file mode 100644 index 00000000000..1fc12d8e07f --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java @@ -0,0 +1,499 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoUnit.NANOS; + +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.zone.ZoneRules; +import java.util.Comparator; +import java.util.Objects; + +/** + * A date-time without a time-zone in an arbitrary chronology, intended + * for advanced globalization use cases. + *

    + * Most applications should declare method signatures, fields and variables + * as {@link LocalDateTime}, not this interface. + *

    + * A {@code ChronoLocalDateTime} is the abstract representation of a local date-time + * where the {@code Chrono chronology}, or calendar system, is pluggable. + * The date-time is defined in terms of fields expressed by {@link TemporalField}, + * where most common implementations are defined in {@link ChronoField}. + * The chronology defines how the calendar system operates and the meaning of + * the standard fields. + * + *

    When to use this interface

    + * The design of the API encourages the use of {@code LocalDateTime} rather than this + * interface, even in the case where the application needs to deal with multiple + * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}. + *

    + * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood + * before using this interface. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + * + * @param the chronology of this date-time + * @since 1.8 + */ +public interface ChronoLocalDateTime> + extends Temporal, TemporalAdjuster, Comparable> { + + /** + * Comparator for two {@code ChronoLocalDateTime} instances ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * + * @see #isAfter + * @see #isBefore + * @see #isEqual + */ + Comparator> DATE_TIME_COMPARATOR = + new Comparator>() { + @Override + public int compare(ChronoLocalDateTime datetime1, ChronoLocalDateTime datetime2) { + int cmp = Long.compare(datetime1.getDate().toEpochDay(), datetime2.getDate().toEpochDay()); + if (cmp == 0) { + cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay()); + } + return cmp; + } + }; + + /** + * Gets the local date part of this date-time. + *

    + * This returns a local date with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + ChronoLocalDate getDate() ; + + /** + * Gets the local time part of this date-time. + *

    + * This returns a local time with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + LocalTime getTime(); + + + //----------------------------------------------------------------------- + // override for covariant return type + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDateTime with(TemporalAdjuster adjuster) { + return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.with(adjuster)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + ChronoLocalDateTime with(TemporalField field, long newValue); + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDateTime plus(TemporalAdder adder) { + return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.plus(adder)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + ChronoLocalDateTime plus(long amountToAdd, TemporalUnit unit); + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDateTime minus(TemporalSubtractor subtractor) { + return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(subtractor)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoLocalDateTime minus(long amountToSubtract, TemporalUnit unit) { + return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Queries this date-time using the specified query. + *

    + * This queries this date-time using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public default R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) getDate().getChrono(); + } + if (query == Queries.precision()) { + return (R) NANOS; + } + // inline TemporalAccessor.super.query(query) as an optimization + if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { + return null; + } + return query.queryFrom(this); + } + + /** + * Adjusts the specified temporal object to have the same date and time as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the date and time changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#EPOCH_DAY} and + * {@link ChronoField#NANO_OF_DAY} as the fields. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisLocalDateTime.adjustInto(temporal);
    +     *   temporal = temporal.with(thisLocalDateTime);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public default Temporal adjustInto(Temporal temporal) { + return temporal + .with(EPOCH_DAY, getDate().toEpochDay()) + .with(NANO_OF_DAY, getTime().toNanoOfDay()); + } + + //----------------------------------------------------------------------- + /** + * Returns a zoned date-time formed from this date-time and the specified time-zone. + *

    + * This creates a zoned date-time matching the input date-time as closely as possible. + * Time-zone rules, such as daylight savings, mean that not every local date-time + * is valid for the specified zone, thus the local date-time may be adjusted. + *

    + * The local date-time is resolved to a single instant on the time-line. + * This is achieved by finding a valid offset from UTC/Greenwich for the local + * date-time as defined by the {@link ZoneRules rules} of the zone ID. + *

    + * In most cases, there is only one valid offset for a local date-time. + * In the case of an overlap, where clocks are set back, there are two valid offsets. + * This method uses the earlier offset typically corresponding to "summer". + *

    + * In the case of a gap, where clocks jump forward, there is no valid offset. + * Instead, the local date-time is adjusted to be later by the length of the gap. + * For a typical one hour daylight savings change, the local date-time will be + * moved one hour later into the offset typically corresponding to "summer". + *

    + * To obtain the later offset during an overlap, call + * {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param zone the time-zone to use, not null + * @return the zoned date-time formed from this date-time, not null + */ + ChronoZonedDateTime atZone(ZoneId zone); + + //----------------------------------------------------------------------- + /** + * Converts this date-time to an {@code Instant}. + *

    + * This combines this local date-time and the specified offset to form + * an {@code Instant}. + *

    + * This default implementation calculates from the epoch-day of the date and the + * second-of-day of the time. + * + * @param offset the offset to use for the conversion, not null + * @return an {@code Instant} representing the same instant, not null + */ + public default Instant toInstant(ZoneOffset offset) { + return Instant.ofEpochSecond(toEpochSecond(offset), getTime().getNano()); + } + + /** + * Converts this date-time to the number of seconds from the epoch + * of 1970-01-01T00:00:00Z. + *

    + * This combines this local date-time and the specified offset to calculate the + * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier are negative. + *

    + * This default implementation calculates from the epoch-day of the date and the + * second-of-day of the time. + * + * @param offset the offset to use for the conversion, not null + * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z + */ + public default long toEpochSecond(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + long epochDay = getDate().toEpochDay(); + long secs = epochDay * 86400 + getTime().toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + + //----------------------------------------------------------------------- + /** + * Compares this date-time to another date-time, including the chronology. + *

    + * The comparison is based first on the underlying time-line date-time, then + * on the chronology. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * For example, the following is the comparator order: + *

      + *
    1. {@code 2012-12-03T12:00 (ISO)}
    2. + *
    3. {@code 2012-12-04T12:00 (ISO)}
    4. + *
    5. {@code 2555-12-04T12:00 (ThaiBuddhist)}
    6. + *
    7. {@code 2012-12-05T12:00 (ISO)}
    8. + *
    + * Values #2 and #3 represent the same date-time on the time-line. + * When two values represent the same date-time, the chronology ID is compared to distinguish them. + * This step is needed to make the ordering "consistent with equals". + *

    + * If all the date-time objects being compared are in the same chronology, then the + * additional chronology stage is not required and only the local date-time is used. + *

    + * This default implementation performs the comparison defined above. + * + * @param other the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public default int compareTo(ChronoLocalDateTime other) { + int cmp = getDate().compareTo(other.getDate()); + if (cmp == 0) { + cmp = getTime().compareTo(other.getTime()); + if (cmp == 0) { + cmp = getDate().getChrono().compareTo(other.getDate().getChrono()); + } + } + return cmp; + } + + /** + * Checks if this date-time is after the specified date-time ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date-time and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + *

    + * This default implementation performs the comparison based on the epoch-day + * and nano-of-day. + * + * @param other the other date-time to compare to, not null + * @return true if this is after the specified date-time + */ + public default boolean isAfter(ChronoLocalDateTime other) { + long thisEpDay = this.getDate().toEpochDay(); + long otherEpDay = other.getDate().toEpochDay(); + return thisEpDay > otherEpDay || + (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() > other.getTime().toNanoOfDay()); + } + + /** + * Checks if this date-time is before the specified date-time ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date-time and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + *

    + * This default implementation performs the comparison based on the epoch-day + * and nano-of-day. + * + * @param other the other date-time to compare to, not null + * @return true if this is before the specified date-time + */ + public default boolean isBefore(ChronoLocalDateTime other) { + long thisEpDay = this.getDate().toEpochDay(); + long otherEpDay = other.getDate().toEpochDay(); + return thisEpDay < otherEpDay || + (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() < other.getTime().toNanoOfDay()); + } + + /** + * Checks if this date-time is equal to the specified date-time ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and time and not the chronology. + * This allows date-times in different calendar systems to be compared based + * on the time-line position. + *

    + * This default implementation performs the comparison based on the epoch-day + * and nano-of-day. + * + * @param other the other date-time to compare to, not null + * @return true if the underlying date-time is equal to the specified date-time on the timeline + */ + public default boolean isEqual(ChronoLocalDateTime other) { + // Do the time check first, it is cheaper than computing EPOCH day. + return this.getTime().toNanoOfDay() == other.getTime().toNanoOfDay() && + this.getDate().toEpochDay() == other.getDate().toEpochDay(); + } + + /** + * Checks if this date-time is equal to another date-time, including the chronology. + *

    + * Compares this date-time with another ensuring that the date-time and chronology are the same. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + boolean equals(Object obj); + + /** + * A hash code for this date-time. + * + * @return a suitable hash code + */ + @Override + int hashCode(); + + //----------------------------------------------------------------------- + /** + * Outputs this date-time as a {@code String}. + *

    + * The output will include the full local date-time and the chronology ID. + * + * @return a string representation of this date-time, not null + */ + @Override + String toString(); + + /** + * Outputs this date-time as a {@code String} using the formatter. + *

    + * The default implementation must behave as follows: + *

    +     *  return formatter.print(this);
    +     * 
    + * + * @param formatter the formatter to use, not null + * @return the formatted date-time string, not null + * @throws DateTimeException if an error occurs during printing + */ + public default String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java new file mode 100644 index 00000000000..4baeec053f2 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java @@ -0,0 +1,426 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.Objects; + +/** + * A date-time without a time-zone for the calendar neutral API. + *

    + * {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often + * viewed as year-month-day-hour-minute-second. This object can also access other + * fields such as day-of-year, day-of-week and week-of-year. + *

    + * This class stores all date and time fields, to a precision of nanoseconds. + * It does not store or represent a time-zone. For example, the value + * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @param the chronology of this date + * @since 1.8 + */ +final class ChronoLocalDateTimeImpl> + implements ChronoLocalDateTime, Temporal, TemporalAdjuster, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 4556003607393004514L; + /** + * Hours per day. + */ + static final int HOURS_PER_DAY = 24; + /** + * Minutes per hour. + */ + static final int MINUTES_PER_HOUR = 60; + /** + * Minutes per day. + */ + static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; + /** + * Seconds per minute. + */ + static final int SECONDS_PER_MINUTE = 60; + /** + * Seconds per hour. + */ + static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + /** + * Seconds per day. + */ + static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; + /** + * Milliseconds per day. + */ + static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L; + /** + * Microseconds per day. + */ + static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L; + /** + * Nanos per second. + */ + static final long NANOS_PER_SECOND = 1000_000_000L; + /** + * Nanos per minute. + */ + static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE; + /** + * Nanos per hour. + */ + static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR; + /** + * Nanos per day. + */ + static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY; + + /** + * The date part. + */ + private final ChronoLocalDate date; + /** + * The time part. + */ + private final LocalTime time; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code ChronoLocalDateTime} from a date and time. + * + * @param date the local date, not null + * @param time the local time, not null + * @return the local date-time, not null + */ + static > ChronoLocalDateTimeImpl of(ChronoLocalDate date, LocalTime time) { + return new ChronoLocalDateTimeImpl<>(date, time); + } + + /** + * Constructor. + * + * @param date the date part of the date-time, not null + * @param time the time part of the date-time, not null + */ + private ChronoLocalDateTimeImpl(ChronoLocalDate date, LocalTime time) { + Objects.requireNonNull(date, "date"); + Objects.requireNonNull(time, "time"); + this.date = date; + this.time = time; + } + + /** + * Returns a copy of this date-time with the new date and time, checking + * to see if a new object is in fact required. + * + * @param newDate the date of the new date-time, not null + * @param newTime the time of the new date-time, not null + * @return the date-time, not null + */ + private ChronoLocalDateTimeImpl with(Temporal newDate, LocalTime newTime) { + if (date == newDate && time == newTime) { + return this; + } + // Validate that the new Temporal is a ChronoLocalDate (and not something else) + ChronoLocalDate cd = date.getChrono().ensureChronoLocalDate(newDate); + return new ChronoLocalDateTimeImpl<>(cd, newTime); + } + + //----------------------------------------------------------------------- + @Override + public ChronoLocalDate getDate() { + return date; + } + + @Override + public LocalTime getTime() { + return time; + } + + //----------------------------------------------------------------------- + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + return f.isDateField() || f.isTimeField(); + } + return field != null && field.doIsSupported(this); + } + + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + return (f.isTimeField() ? time.range(field) : date.range(field)); + } + return field.doRange(this); + } + + @Override + public int get(TemporalField field) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + return (f.isTimeField() ? time.get(field) : date.get(field)); + } + return range(field).checkValidIntValue(getLong(field), field); + } + + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + return (f.isTimeField() ? time.getLong(field) : date.getLong(field)); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + @SuppressWarnings("unchecked") + @Override + public ChronoLocalDateTimeImpl with(TemporalAdjuster adjuster) { + if (adjuster instanceof ChronoLocalDate) { + // The Chrono is checked in with(date,time) + return with((ChronoLocalDate) adjuster, time); + } else if (adjuster instanceof LocalTime) { + return with(date, (LocalTime) adjuster); + } else if (adjuster instanceof ChronoLocalDateTimeImpl) { + return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster); + } + return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster.adjustInto(this)); + } + + @Override + public ChronoLocalDateTimeImpl with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + if (f.isTimeField()) { + return with(date, time.with(field, newValue)); + } else { + return with(date.with(field, newValue), time); + } + } + return date.getChrono().ensureChronoLocalDateTime(field.doWith(this, newValue)); + } + + //----------------------------------------------------------------------- + @Override + public ChronoLocalDateTimeImpl plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + ChronoUnit f = (ChronoUnit) unit; + switch (f) { + case NANOS: return plusNanos(amountToAdd); + case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000); + case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000); + case SECONDS: return plusSeconds(amountToAdd); + case MINUTES: return plusMinutes(amountToAdd); + case HOURS: return plusHours(amountToAdd); + case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12); // no overflow (256 is multiple of 2) + } + return with(date.plus(amountToAdd, unit), time); + } + return date.getChrono().ensureChronoLocalDateTime(unit.doPlus(this, amountToAdd)); + } + + private ChronoLocalDateTimeImpl plusDays(long days) { + return with(date.plus(days, ChronoUnit.DAYS), time); + } + + private ChronoLocalDateTimeImpl plusHours(long hours) { + return plusWithOverflow(date, hours, 0, 0, 0); + } + + private ChronoLocalDateTimeImpl plusMinutes(long minutes) { + return plusWithOverflow(date, 0, minutes, 0, 0); + } + + ChronoLocalDateTimeImpl plusSeconds(long seconds) { + return plusWithOverflow(date, 0, 0, seconds, 0); + } + + private ChronoLocalDateTimeImpl plusNanos(long nanos) { + return plusWithOverflow(date, 0, 0, 0, nanos); + } + + //----------------------------------------------------------------------- + private ChronoLocalDateTimeImpl plusWithOverflow(ChronoLocalDate newDate, long hours, long minutes, long seconds, long nanos) { + // 9223372036854775808 long, 2147483648 int + if ((hours | minutes | seconds | nanos) == 0) { + return with(newDate, time); + } + long totDays = nanos / NANOS_PER_DAY + // max/24*60*60*1B + seconds / SECONDS_PER_DAY + // max/24*60*60 + minutes / MINUTES_PER_DAY + // max/24*60 + hours / HOURS_PER_DAY; // max/24 + long totNanos = nanos % NANOS_PER_DAY + // max 86400000000000 + (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND + // max 86400000000000 + (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE + // max 86400000000000 + (hours % HOURS_PER_DAY) * NANOS_PER_HOUR; // max 86400000000000 + long curNoD = time.toNanoOfDay(); // max 86400000000000 + totNanos = totNanos + curNoD; // total 432000000000000 + totDays += Math.floorDiv(totNanos, NANOS_PER_DAY); + long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY); + LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD)); + return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime); + } + + //----------------------------------------------------------------------- + @Override + public ChronoZonedDateTime atZone(ZoneId zone) { + return ChronoZonedDateTimeImpl.ofBest(this, zone, null); + } + + //----------------------------------------------------------------------- + @Override + public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + if (endDateTime instanceof ChronoLocalDateTime == false) { + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + @SuppressWarnings("unchecked") + ChronoLocalDateTime end = (ChronoLocalDateTime) endDateTime; + if (getDate().getChrono().equals(end.getDate().getChrono()) == false) { + throw new DateTimeException("Unable to calculate period between two different chronologies"); + } + if (unit instanceof ChronoUnit) { + ChronoUnit f = (ChronoUnit) unit; + if (f.isTimeUnit()) { + long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY); + switch (f) { + case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break; + case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break; + case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break; + case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break; + case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break; + case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break; + case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break; + } + return Math.addExact(amount, time.periodUntil(end.getTime(), unit)); + } + ChronoLocalDate endDate = end.getDate(); + if (end.getTime().isBefore(time)) { + endDate = endDate.minus(1, ChronoUnit.DAYS); + } + return date.periodUntil(endDate, unit); + } + return unit.between(this, endDateTime).getAmount(); + } + + //----------------------------------------------------------------------- + private Object writeReplace() { + return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(date); + out.writeObject(time); + } + + static ChronoLocalDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + ChronoLocalDate date = (ChronoLocalDate) in.readObject(); + LocalTime time = (LocalTime) in.readObject(); + return date.atTime(time); + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ChronoLocalDateTime) { + return compareTo((ChronoLocalDateTime) obj) == 0; + } + return false; + } + + @Override + public int hashCode() { + return getDate().hashCode() ^ getTime().hashCode(); + } + + @Override + public String toString() { + return getDate().toString() + 'T' + getTime().toString(); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java new file mode 100644 index 00000000000..33f1318bbf6 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.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. 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) 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 java.time.temporal; + +import java.time.Duration; + +/** + * A standard set of date periods units. + *

    + * This set of units provide unit-based access to manipulate a date, time or date-time. + * The standard set of units can be extended by implementing {@link TemporalUnit}. + *

    + * These units are intended to be applicable in multiple calendar systems. + * For example, most non-ISO calendar systems define units of years, months and days, + * just with slightly different rules. + * The documentation of each unit explains how it operates. + * + *

    Specification for implementors

    + * This is a final, immutable and thread-safe enum. + * + * @since 1.8 + */ +public enum ChronoUnit implements TemporalUnit { + + /** + * Unit that represents the concept of a nanosecond, the smallest supported unit of time. + * For the ISO calendar system, it is equal to the 1,000,000,000th part of the second unit. + */ + NANOS("Nanos", Duration.ofNanos(1)), + /** + * Unit that represents the concept of a microsecond. + * For the ISO calendar system, it is equal to the 1,000,000th part of the second unit. + */ + MICROS("Micros", Duration.ofNanos(1000)), + /** + * Unit that represents the concept of a millisecond. + * For the ISO calendar system, it is equal to the 1000th part of the second unit. + */ + MILLIS("Millis", Duration.ofNanos(1000_000)), + /** + * Unit that represents the concept of a second. + * For the ISO calendar system, it is equal to the second in the SI system + * of units, except around a leap-second. + */ + SECONDS("Seconds", Duration.ofSeconds(1)), + /** + * Unit that represents the concept of a minute. + * For the ISO calendar system, it is equal to 60 seconds. + */ + MINUTES("Minutes", Duration.ofSeconds(60)), + /** + * Unit that represents the concept of an hour. + * For the ISO calendar system, it is equal to 60 minutes. + */ + HOURS("Hours", Duration.ofSeconds(3600)), + /** + * Unit that represents the concept of half a day, as used in AM/PM. + * For the ISO calendar system, it is equal to 12 hours. + */ + HALF_DAYS("HalfDays", Duration.ofSeconds(43200)), + /** + * Unit that represents the concept of a day. + * For the ISO calendar system, it is the standard day from midnight to midnight. + * The estimated duration of a day is {@code 24 Hours}. + *

    + * When used with other calendar systems it must correspond to the day defined by + * the rising and setting of the Sun on Earth. It is not required that days begin + * at midnight - when converting between calendar systems, the date should be + * equivalent at midday. + */ + DAYS("Days", Duration.ofSeconds(86400)), + /** + * Unit that represents the concept of a week. + * For the ISO calendar system, it is equal to 7 days. + *

    + * When used with other calendar systems it must correspond to an integral number of days. + */ + WEEKS("Weeks", Duration.ofSeconds(7 * 86400L)), + /** + * Unit that represents the concept of a month. + * For the ISO calendar system, the length of the month varies by month-of-year. + * The estimated duration of a month is one twelfth of {@code 365.2425 Days}. + *

    + * When used with other calendar systems it must correspond to an integral number of days. + */ + MONTHS("Months", Duration.ofSeconds(31556952L / 12)), + /** + * Unit that represents the concept of a year. + * For the ISO calendar system, it is equal to 12 months. + * The estimated duration of a year is {@code 365.2425 Days}. + *

    + * When used with other calendar systems it must correspond to an integral number of days + * or months roughly equal to a year defined by the passage of the Earth around the Sun. + */ + YEARS("Years", Duration.ofSeconds(31556952L)), + /** + * Unit that represents the concept of a decade. + * For the ISO calendar system, it is equal to 10 years. + *

    + * When used with other calendar systems it must correspond to an integral number of days + * and is normally an integral number of years. + */ + DECADES("Decades", Duration.ofSeconds(31556952L * 10L)), + /** + * Unit that represents the concept of a century. + * For the ISO calendar system, it is equal to 100 years. + *

    + * When used with other calendar systems it must correspond to an integral number of days + * and is normally an integral number of years. + */ + CENTURIES("Centuries", Duration.ofSeconds(31556952L * 100L)), + /** + * Unit that represents the concept of a millennium. + * For the ISO calendar system, it is equal to 1000 years. + *

    + * When used with other calendar systems it must correspond to an integral number of days + * and is normally an integral number of years. + */ + MILLENNIA("Millennia", Duration.ofSeconds(31556952L * 1000L)), + /** + * Unit that represents the concept of an era. + * The ISO calendar system doesn't have eras thus it is impossible to add + * an era to a date or date-time. + * The estimated duration of the era is artificially defined as {@code 1,000,00,000 Years}. + *

    + * When used with other calendar systems there are no restrictions on the unit. + */ + ERAS("Eras", Duration.ofSeconds(31556952L * 1000_000_000L)), + /** + * Artificial unit that represents the concept of forever. + * This is primarily used with {@link TemporalField} to represent unbounded fields + * such as the year or era. + * The estimated duration of the era is artificially defined as the largest duration + * supported by {@code Duration}. + */ + FOREVER("Forever", Duration.ofSeconds(Long.MAX_VALUE, 999_999_999)); + + private final String name; + private final Duration duration; + + private ChronoUnit(String name, Duration estimatedDuration) { + this.name = name; + this.duration = estimatedDuration; + } + + //----------------------------------------------------------------------- + @Override + public String getName() { + return name; + } + + //----------------------------------------------------------------------- + /** + * Gets the estimated duration of this unit in the ISO calendar system. + *

    + * All of the units in this class have an estimated duration. + * Days vary due to daylight saving time, while months have different lengths. + * + * @return the estimated duration of this unit, not null + */ + @Override + public Duration getDuration() { + return duration; + } + + /** + * Checks if the duration of the unit is an estimate. + *

    + * All time units in this class are considered to be accurate, while all date + * units in this class are considered to be estimated. + *

    + * This definition ignores leap seconds, but considers that Days vary due to + * daylight saving time and months have different lengths. + * + * @return true if the duration is estimated, false if accurate + */ + @Override + public boolean isDurationEstimated() { + return isDateUnit(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this unit is a date unit. + * + * @return true if a date unit, false if a time unit + */ + public boolean isDateUnit() { + return this.compareTo(DAYS) >= 0; + } + + /** + * Checks if this unit is a time unit. + * + * @return true if a time unit, false if a date unit + */ + public boolean isTimeUnit() { + return this.compareTo(DAYS) < 0; + } + + //----------------------------------------------------------------------- + @Override + public boolean isSupported(Temporal temporal) { + if (this == FOREVER) { + return false; + } + if (temporal instanceof ChronoLocalDate) { + return isDateUnit(); + } + if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { + return true; + } + return TemporalUnit.super.isSupported(temporal); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) dateTime.plus(periodToAdd, this); + } + + //----------------------------------------------------------------------- + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + return new SimplePeriod(dateTime1.periodUntil(dateTime2, this), this); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + return getName(); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java new file mode 100644 index 00000000000..9e172ef7fda --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java @@ -0,0 +1,564 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.NANOS; + +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Comparator; +import java.util.Objects; + +/** + * A date-time with a time-zone in an arbitrary chronology, + * intended for advanced globalization use cases. + *

    + * Most applications should declare method signatures, fields and variables + * as {@link ZonedDateTime}, not this interface. + *

    + * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time + * where the {@code Chrono chronology}, or calendar system, is pluggable. + * The date-time is defined in terms of fields expressed by {@link TemporalField}, + * where most common implementations are defined in {@link ChronoField}. + * The chronology defines how the calendar system operates and the meaning of + * the standard fields. + * + *

    When to use this interface

    + * The design of the API encourages the use of {@code ZonedDateTime} rather than this + * interface, even in the case where the application needs to deal with multiple + * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}. + *

    + * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood + * before using this interface. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + * + * @param the chronology of this date-time + * @since 1.8 + */ +public interface ChronoZonedDateTime> + extends Temporal, Comparable> { + + /** + * Comparator for two {@code ChronoZonedDateTime} instances ignoring the chronology. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying date and not the chronology. + * This allows dates in different calendar systems to be compared based + * on the time-line position. + * + * @see #isAfter + * @see #isBefore + * @see #isEqual + */ + Comparator> INSTANT_COMPARATOR = new Comparator>() { + @Override + public int compare(ChronoZonedDateTime datetime1, ChronoZonedDateTime datetime2) { + int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); + if (cmp == 0) { + cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay()); + } + return cmp; + } + }; + + @Override + public default ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { + return field.range(); + } + return getDateTime().range(field); + } + return field.doRange(this); + } + + @Override + public default int get(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field); + case OFFSET_SECONDS: return getOffset().getTotalSeconds(); + } + return getDateTime().get(field); + } + return Temporal.super.get(field); + } + + @Override + public default long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case INSTANT_SECONDS: return toEpochSecond(); + case OFFSET_SECONDS: return getOffset().getTotalSeconds(); + } + return getDateTime().getLong(field); + } + return field.doGet(this); + } + + /** + * Gets the local date part of this date-time. + *

    + * This returns a local date with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public default ChronoLocalDate getDate() { + return getDateTime().getDate(); + } + + /** + * Gets the local time part of this date-time. + *

    + * This returns a local time with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public default LocalTime getTime() { + return getDateTime().getTime(); + } + + /** + * Gets the local date-time part of this date-time. + *

    + * This returns a local date with the same year, month and day + * as this date-time. + * + * @return the local date-time part of this date-time, not null + */ + ChronoLocalDateTime getDateTime(); + + /** + * Gets the zone offset, such as '+01:00'. + *

    + * This is the offset of the local date-time from UTC/Greenwich. + * + * @return the zone offset, not null + */ + ZoneOffset getOffset(); + + /** + * Gets the zone ID, such as 'Europe/Paris'. + *

    + * This returns the stored time-zone id used to determine the time-zone rules. + * + * @return the zone ID, not null + */ + ZoneId getZone(); + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date-time changing the zone offset to the + * earlier of the two valid offsets at a local time-line overlap. + *

    + * This method only has any effect when the local time-line overlaps, such as + * at an autumn daylight savings cutover. In this scenario, there are two + * valid offsets for the local date-time. Calling this method will return + * a zoned date-time with the earlier of the two selected. + *

    + * If this method is called when it is not an overlap, {@code this} + * is returned. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a {@code ZoneChronoDateTime} based on this date-time with the earlier offset, not null + * @throws DateTimeException if no rules can be found for the zone + * @throws DateTimeException if no rules are valid for this date-time + */ + ChronoZonedDateTime withEarlierOffsetAtOverlap(); + + /** + * Returns a copy of this date-time changing the zone offset to the + * later of the two valid offsets at a local time-line overlap. + *

    + * This method only has any effect when the local time-line overlaps, such as + * at an autumn daylight savings cutover. In this scenario, there are two + * valid offsets for the local date-time. Calling this method will return + * a zoned date-time with the later of the two selected. + *

    + * If this method is called when it is not an overlap, {@code this} + * is returned. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a {@code ChronoZonedDateTime} based on this date-time with the later offset, not null + * @throws DateTimeException if no rules can be found for the zone + * @throws DateTimeException if no rules are valid for this date-time + */ + ChronoZonedDateTime withLaterOffsetAtOverlap(); + + /** + * Returns a copy of this ZonedDateTime with a different time-zone, + * retaining the local date-time if possible. + *

    + * This method changes the time-zone and retains the local date-time. + * The local date-time is only changed if it is invalid for the new zone. + *

    + * To change the zone and adjust the local date-time, + * use {@link #withZoneSameInstant(ZoneId)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param zone the time-zone to change to, not null + * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null + */ + ChronoZonedDateTime withZoneSameLocal(ZoneId zone); + + /** + * Returns a copy of this date-time with a different time-zone, + * retaining the instant. + *

    + * This method changes the time-zone and retains the instant. + * This normally results in a change to the local date-time. + *

    + * This method is based on retaining the same instant, thus gaps and overlaps + * in the local time-line have no effect on the result. + *

    + * To change the offset while keeping the local time, + * use {@link #withZoneSameLocal(ZoneId)}. + * + * @param zone the time-zone to change to, not null + * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + ChronoZonedDateTime withZoneSameInstant(ZoneId zone); + + //----------------------------------------------------------------------- + // override for covariant return type + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoZonedDateTime with(TemporalAdjuster adjuster) { + return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.with(adjuster)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + ChronoZonedDateTime with(TemporalField field, long newValue); + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoZonedDateTime plus(TemporalAdder adder) { + return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.plus(adder)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + ChronoZonedDateTime plus(long amountToAdd, TemporalUnit unit); + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoZonedDateTime minus(TemporalSubtractor subtractor) { + return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(subtractor)); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public default ChronoZonedDateTime minus(long amountToSubtract, TemporalUnit unit) { + return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Queries this date-time using the specified query. + *

    + * This queries this date-time using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public default R query(TemporalQuery query) { + if (query == Queries.zone() || query == Queries.zoneId()) { + return (R) getZone(); + } else if (query == Queries.chrono()) { + return (R) getDate().getChrono(); + } else if (query == Queries.precision()) { + return (R) NANOS; + } else if (query == Queries.offset()) { + return (R) getOffset(); + } + // inline TemporalAccessor.super.query(query) as an optimization + return query.queryFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Converts this date-time to an {@code Instant}. + *

    + * This combines the {@linkplain #getDateTime() local date-time} and + * {@linkplain #getOffset() offset} to form an {@code Instant}. + * + * @return an {@code Instant} representing the same instant, not null + */ + public default Instant toInstant() { + return Instant.ofEpochSecond(toEpochSecond(), getTime().getNano()); + } + + /** + * Converts this date-time to the number of seconds from the epoch + * of 1970-01-01T00:00:00Z. + *

    + * This uses the {@linkplain #getDateTime() local date-time} and + * {@linkplain #getOffset() offset} to calculate the epoch-second value, + * which is the number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier are negative. + * + * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z + */ + public default long toEpochSecond() { + long epochDay = getDate().toEpochDay(); + long secs = epochDay * 86400 + getTime().toSecondOfDay(); + secs -= getOffset().getTotalSeconds(); + return secs; + } + + //----------------------------------------------------------------------- + /** + * Compares this date-time to another date-time, including the chronology. + *

    + * The comparison is based first on the instant, then on the local date-time, + * then on the zone ID, then on the chronology. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * If all the date-time objects being compared are in the same chronology, then the + * additional chronology stage is not required. + *

    + * This default implementation performs the comparison defined above. + * + * @param other the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public default int compareTo(ChronoZonedDateTime other) { + int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); + if (cmp == 0) { + cmp = getTime().getNano() - other.getTime().getNano(); + if (cmp == 0) { + cmp = getDateTime().compareTo(other.getDateTime()); + if (cmp == 0) { + cmp = getZone().getId().compareTo(other.getZone().getId()); + if (cmp == 0) { + cmp = getDate().getChrono().compareTo(other.getDate().getChrono()); + } + } + } + } + return cmp; + } + + /** + * Checks if the instant of this date-time is before that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. + *

    + * This default implementation performs the comparison based on the epoch-second + * and nano-of-second. + * + * @param other the other date-time to compare to, not null + * @return true if this point is before the specified date-time + */ + public default boolean isBefore(ChronoZonedDateTime other) { + long thisEpochSec = toEpochSecond(); + long otherEpochSec = other.toEpochSecond(); + return thisEpochSec < otherEpochSec || + (thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano()); + } + + /** + * Checks if the instant of this date-time is after that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. + *

    + * This default implementation performs the comparison based on the epoch-second + * and nano-of-second. + * + * @param other the other date-time to compare to, not null + * @return true if this is after the specified date-time + */ + public default boolean isAfter(ChronoZonedDateTime other) { + long thisEpochSec = toEpochSecond(); + long otherEpochSec = other.toEpochSecond(); + return thisEpochSec > otherEpochSec || + (thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano()); + } + + /** + * Checks if the instant of this date-time is equal to that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} and {@link #equals} + * in that it only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. + *

    + * This default implementation performs the comparison based on the epoch-second + * and nano-of-second. + * + * @param other the other date-time to compare to, not null + * @return true if the instant equals the instant of the specified date-time + */ + public default boolean isEqual(ChronoZonedDateTime other) { + return toEpochSecond() == other.toEpochSecond() && + getTime().getNano() == other.getTime().getNano(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this date-time is equal to another date-time. + *

    + * The comparison is based on the offset date-time and the zone. + * To compare for the same instant on the time-line, use {@link #compareTo}. + * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date-time + */ + @Override + boolean equals(Object obj); + + /** + * A hash code for this date-time. + * + * @return a suitable hash code + */ + @Override + int hashCode(); + + //----------------------------------------------------------------------- + /** + * Outputs this date-time as a {@code String}. + *

    + * The output will include the full zoned date-time and the chronology ID. + * + * @return a string representation of this date-time, not null + */ + @Override + String toString(); + + /** + * Outputs this date-time as a {@code String} using the formatter. + *

    + * The default implementation must behave as follows: + *

    +     *  return formatter.print(this);
    +     * 
    + * + * @param formatter the formatter to use, not null + * @return the formatted date-time string, not null + * @throws DateTimeException if an error occurs during printing + */ + public default String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java new file mode 100644 index 00000000000..27efde35d06 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java @@ -0,0 +1,353 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneRules; +import java.util.List; +import java.util.Objects; + +/** + * A date-time with a time-zone in the calendar neutral API. + *

    + * {@code ZoneChronoDateTime} is an immutable representation of a date-time with a time-zone. + * This class stores all date and time fields, to a precision of nanoseconds, + * as well as a time-zone and zone offset. + *

    + * The purpose of storing the time-zone is to distinguish the ambiguous case where + * the local time-line overlaps, typically as a result of the end of daylight time. + * Information about the local-time can be obtained using methods on the time-zone. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @param the chronology of this date + * @since 1.8 + */ +final class ChronoZonedDateTimeImpl> + implements ChronoZonedDateTime, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -5261813987200935591L; + + /** + * The local date-time. + */ + private final ChronoLocalDateTimeImpl dateTime; + /** + * The zone offset. + */ + private final ZoneOffset offset; + /** + * The zone ID. + */ + private final ZoneId zone; + + //----------------------------------------------------------------------- + /** + * Obtains an instance from a local date-time using the preferred offset if possible. + * + * @param localDateTime the local date-time, not null + * @param zone the zone identifier, not null + * @param preferredOffset the zone offset, null if no preference + * @return the zoned date-time, not null + */ + static > ChronoZonedDateTime ofBest( + ChronoLocalDateTimeImpl localDateTime, ZoneId zone, ZoneOffset preferredOffset) { + Objects.requireNonNull(localDateTime, "localDateTime"); + Objects.requireNonNull(zone, "zone"); + if (zone instanceof ZoneOffset) { + return new ChronoZonedDateTimeImpl(localDateTime, (ZoneOffset) zone, zone); + } + ZoneRules rules = zone.getRules(); + LocalDateTime isoLDT = LocalDateTime.from(localDateTime); + List validOffsets = rules.getValidOffsets(isoLDT); + ZoneOffset offset; + if (validOffsets.size() == 1) { + offset = validOffsets.get(0); + } else if (validOffsets.size() == 0) { + ZoneOffsetTransition trans = rules.getTransition(isoLDT); + localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds()); + offset = trans.getOffsetAfter(); + } else { + if (preferredOffset != null && validOffsets.contains(preferredOffset)) { + offset = preferredOffset; + } else { + offset = validOffsets.get(0); + } + } + Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules + return new ChronoZonedDateTimeImpl(localDateTime, offset, zone); + } + + /** + * Obtains an instance from an instant using the specified time-zone. + * + * @param chrono the chronology, not null + * @param instant the instant, not null + * @param zone the zone identifier, not null + * @return the zoned date-time, not null + */ + static > ChronoZonedDateTimeImpl ofInstant(Chrono chrono, Instant instant, ZoneId zone) { + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules + LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); + ChronoLocalDateTimeImpl cldt = (ChronoLocalDateTimeImpl) chrono.localDateTime(ldt); + return new ChronoZonedDateTimeImpl(cldt, offset, zone); + } + + /** + * Obtains an instance from an {@code Instant}. + * + * @param instant the instant to create the date-time from, not null + * @param zone the time-zone to use, validated not null + * @return the zoned date-time, validated not null + */ + private ChronoZonedDateTimeImpl create(Instant instant, ZoneId zone) { + return ofInstant(getDate().getChrono(), instant, zone); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param dateTime the date-time, not null + * @param offset the zone offset, not null + * @param zone the zone ID, not null + */ + private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl dateTime, ZoneOffset offset, ZoneId zone) { + this.dateTime = Objects.requireNonNull(dateTime, "dateTime"); + this.offset = Objects.requireNonNull(offset, "offset"); + this.zone = Objects.requireNonNull(zone, "zone"); + } + + //----------------------------------------------------------------------- + public ZoneOffset getOffset() { + return offset; + } + + @Override + public ChronoZonedDateTime withEarlierOffsetAtOverlap() { + ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this)); + if (trans != null && trans.isOverlap()) { + ZoneOffset earlierOffset = trans.getOffsetBefore(); + if (earlierOffset.equals(offset) == false) { + return new ChronoZonedDateTimeImpl(dateTime, earlierOffset, zone); + } + } + return this; + } + + @Override + public ChronoZonedDateTime withLaterOffsetAtOverlap() { + ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this)); + if (trans != null) { + ZoneOffset offset = trans.getOffsetAfter(); + if (offset.equals(getOffset()) == false) { + return new ChronoZonedDateTimeImpl(dateTime, offset, zone); + } + } + return this; + } + + //----------------------------------------------------------------------- + @Override + public ChronoLocalDateTime getDateTime() { + return dateTime; + } + + public ZoneId getZone() { + return zone; + } + + public ChronoZonedDateTime withZoneSameLocal(ZoneId zone) { + return ofBest(dateTime, zone, offset); + } + + @Override + public ChronoZonedDateTime withZoneSameInstant(ZoneId zone) { + Objects.requireNonNull(zone, "zone"); + return this.zone.equals(zone) ? this : create(dateTime.toInstant(offset), zone); + } + + //----------------------------------------------------------------------- + @Override + public boolean isSupported(TemporalField field) { + return field instanceof ChronoField || (field != null && field.doIsSupported(this)); + } + + //----------------------------------------------------------------------- + @Override + public ChronoZonedDateTime with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + switch (f) { + case INSTANT_SECONDS: return plus(newValue - toEpochSecond(), SECONDS); + case OFFSET_SECONDS: { + ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)); + return create(dateTime.toInstant(offset), zone); + } + } + return ofBest(dateTime.with(field, newValue), zone, offset); + } + return getDate().getChrono().ensureChronoZonedDateTime(field.doWith(this, newValue)); + } + + //----------------------------------------------------------------------- + @Override + public ChronoZonedDateTime plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(dateTime.plus(amountToAdd, unit)); + } + return getDate().getChrono().ensureChronoZonedDateTime(unit.doPlus(this, amountToAdd)); /// TODO: Generics replacement Risk! + } + + //----------------------------------------------------------------------- + @Override + public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + if (endDateTime instanceof ChronoZonedDateTime == false) { + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + @SuppressWarnings("unchecked") + ChronoZonedDateTime end = (ChronoZonedDateTime) endDateTime; + if (getDate().getChrono().equals(end.getDate().getChrono()) == false) { + throw new DateTimeException("Unable to calculate period between two different chronologies"); + } + if (unit instanceof ChronoUnit) { + end = end.withZoneSameInstant(offset); + return dateTime.periodUntil(end.getDateTime(), unit); + } + return unit.between(this, endDateTime).getAmount(); + } + + //----------------------------------------------------------------------- + private Object writeReplace() { + return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(dateTime); + out.writeObject(offset); + out.writeObject(zone); + } + + static ChronoZonedDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + ChronoLocalDateTime dateTime = (ChronoLocalDateTime) in.readObject(); + ZoneOffset offset = (ZoneOffset) in.readObject(); + ZoneId zone = (ZoneId) in.readObject(); + return dateTime.atZone(offset).withZoneSameLocal(zone); + // TODO: ZDT uses ofLenient() + } + + //------------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ChronoZonedDateTime) { + return compareTo((ChronoZonedDateTime) obj) == 0; + } + return false; + } + + @Override + public int hashCode() { + return getDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3); + } + + @Override + public String toString() { + String str = getDateTime().toString() + getOffset().toString(); + if (getOffset() != getZone()) { + str += '[' + getZone().toString() + ']'; + } + return str; + } + + +} diff --git a/jdk/src/share/classes/java/time/temporal/Era.java b/jdk/src/share/classes/java/time/temporal/Era.java new file mode 100644 index 00000000000..e32de7473eb --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Era.java @@ -0,0 +1,359 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoUnit.ERAS; + +import java.time.DateTimeException; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.util.Locale; + +/** + * An era of the time-line. + *

    + * Most calendar systems have a single epoch dividing the time-line into two eras. + * However, some calendar systems, have multiple eras, such as one for the reign + * of each leader. + * In all cases, the era is conceptually the largest division of the time-line. + * Each chronology defines the Era's that are known Eras and a + * {@link Chrono#eras Chrono.eras} to get the valid eras. + *

    + * For example, the Thai Buddhist calendar system divides time into two eras, + * before and after a single date. By contrast, the Japanese calendar system + * has one era for the reign of each Emperor. + *

    + * Instances of {@code Era} may be compared using the {@code ==} operator. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations must be singletons - final, immutable and thread-safe. + * It is recommended to use an enum whenever possible. + * + * @param the chronology of the era + * @since 1.8 + */ +public interface Era> extends TemporalAccessor, TemporalAdjuster { + + /** + * Gets the numeric value associated with the era as defined by the chronology. + * Each chronology defines the predefined Eras and methods to list the Eras + * of the chronology. + *

    + * All fields, including eras, have an associated numeric value. + * The meaning of the numeric value for era is determined by the chronology + * according to these principles: + *

      + *
    • The era in use at the epoch 1970-01-01 (ISO) has the value 1. + *
    • Later eras have sequentially higher values. + *
    • Earlier eras have sequentially lower values, which may be negative. + *

    + * + * @return the numeric era value + */ + int getValue(); + + /** + * Gets the chronology of this era. + *

    + * The {@code Chrono} represents the calendar system in use. + * This always returns the standard form of the chronology. + * + * @return the chronology, not null + */ + C getChrono(); + + //----------------------------------------------------------------------- + /** + * Obtains a date in this era given the year-of-era, month, and day. + *

    + * This era is combined with the given date fields to form a date. + * The year specified must be the year-of-era. + * Methods to create a date from the proleptic-year are on {@code Chrono}. + * This always uses the standard form of the chronology. + *

    + * This default implementation invokes the factory method on {@link Chrono}. + * + * @param yearOfEra the calendar system year-of-era + * @param month the calendar system month-of-year + * @param day the calendar system day-of-month + * @return a local date based on this era and the specified year-of-era, month and day + */ + public default ChronoLocalDate date(int yearOfEra, int month, int day) { + return getChrono().date(this, yearOfEra, month, day); + } + + + /** + * Obtains a date in this era given year-of-era and day-of-year fields. + *

    + * This era is combined with the given date fields to form a date. + * The year specified must be the year-of-era. + * Methods to create a date from the proleptic-year are on {@code Chrono}. + * This always uses the standard form of the chronology. + *

    + * This default implementation invokes the factory method on {@link Chrono}. + * + * @param yearOfEra the calendar system year-of-era + * @param dayOfYear the calendar system day-of-year + * @return a local date based on this era and the specified year-of-era and day-of-year + */ + public default ChronoLocalDate dateYearDay(int yearOfEra, int dayOfYear) { + return getChrono().dateYearDay(this, yearOfEra, dayOfYear); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this era can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@code ERA} field returns true. + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this era, false if not + */ + @Override + public default boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == ERA; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This era is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@code ERA} field returns the range. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override // override for Javadoc + public default ValueRange range(TemporalField field) { + return TemporalAccessor.super.range(field); + } + + /** + * Gets the value of the specified field from this era as an {@code int}. + *

    + * This queries this era for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@code ERA} field returns the value of the era. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc and performance + public default int get(TemporalField field) { + if (field == ERA) { + return getValue(); + } + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this era as a {@code long}. + *

    + * This queries this era for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@code ERA} field returns the value of the era. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public default 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); + } + + //----------------------------------------------------------------------- + /** + * Queries this era using the specified query. + *

    + * This queries this era using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public default R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) getChrono(); + } else if (query == Queries.precision()) { + return (R) ERAS; + } + return TemporalAccessor.super.query(query); + } + + /** + * Adjusts the specified temporal object to have the same era as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the era changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link ChronoField#ERA} as the field. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisEra.adjustInto(temporal);
    +     *   temporal = temporal.with(thisEra);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public default Temporal adjustInto(Temporal temporal) { + return temporal.with(ERA, getValue()); + } + + //----------------------------------------------------------------------- + /** + * Gets the textual representation of this era. + *

    + * This returns the textual name used to identify the era. + * The parameters control the style of the returned text and the locale. + *

    + * If no textual mapping is found then the {@link #getValue() numeric value} is returned. + *

    + * This default implementation is suitable for all implementations. + * + * @param style the style of the text required, not null + * @param locale the locale to use, not null + * @return the text value of the era, not null + */ + public default String getText(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this); + } + + // NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese) +} diff --git a/jdk/src/share/classes/java/time/temporal/ISOChrono.java b/jdk/src/share/classes/java/time/temporal/ISOChrono.java new file mode 100644 index 00000000000..c290e4e1dbb --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ISOChrono.java @@ -0,0 +1,399 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +/** + * The ISO calendar system. + *

    + * This chronology defines the rules of the ISO calendar system. + * This calendar system is based on the ISO-8601 standard, which is the + * de facto world calendar. + *

    + * The fields are defined as follows: + *

      + *
    • era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE). + *
    • year-of-era - The year-of-era is the same as the proleptic-year for the current CE era. + * For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards. + *
    • proleptic-year - The proleptic year is the same as the year-of-era for the + * current era. For the previous era, years have zero, then negative values. + *
    • month-of-year - There are 12 months in an ISO year, numbered from 1 to 12. + *
    • day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31. + * Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days. + * Month 2 has 28 days, or 29 in a leap year. + *
    • day-of-year - There are 365 days in a standard ISO year and 366 in a leap year. + * The days are numbered from 1 to 365 or 1 to 366. + *
    • leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400. + *

    + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ISOChrono extends Chrono implements Serializable { + + /** + * Singleton instance of the ISO chronology. + */ + public static final ISOChrono INSTANCE = new ISOChrono(); + /** + * The singleton instance for the era BCE - 'Before Current Era'. + * The 'ISO' part of the name emphasizes that this differs from the BCE + * era in the Gregorian calendar system. + * This has the numeric value of {@code 0}. + */ + public static final Era ERA_BCE = ISOEra.BCE; + /** + * The singleton instance for the era CE - 'Current Era'. + * The 'ISO' part of the name emphasizes that this differs from the CE + * era in the Gregorian calendar system. + * This has the numeric value of {@code 1}. + */ + public static final Era ERA_CE = ISOEra.CE; + + /** + * Serialization version. + */ + private static final long serialVersionUID = -1440403870442975015L; + + /** + * Restricted constructor. + */ + private ISOChrono() { + } + + /** + * Resolve singleton. + * + * @return the singleton instance, not null + */ + private Object readResolve() { + return INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the ID of the chronology - 'ISO'. + *

    + * The ID uniquely identifies the {@code Chrono}. + * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * + * @return the chronology ID - 'ISO' + * @see #getCalendarType() + */ + @Override + public String getId() { + return "ISO"; + } + + /** + * Gets the calendar type of the underlying calendar system - 'iso8601'. + *

    + * 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 also be used as part of a locale, accessible via + * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. + * + * @return the calendar system type - 'iso8601' + * @see #getId() + */ + @Override + public String getCalendarType() { + return "iso8601"; + } + + //----------------------------------------------------------------------- + /** + * Obtains an ISO local date from the era, year-of-era, month-of-year + * and day-of-month fields. + * + * @param era the ISO era, not null + * @param yearOfEra the ISO year-of-era + * @param month the ISO month-of-year + * @param dayOfMonth the ISO day-of-month + * @return the ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + return date(prolepticYear(era, yearOfEra), month, dayOfMonth); + } + + /** + * Obtains an ISO local date from the proleptic-year, month-of-year + * and day-of-month fields. + *

    + * This is equivalent to {@link LocalDate#of(int, int, int)}. + * + * @param prolepticYear the ISO proleptic-year + * @param month the ISO month-of-year + * @param dayOfMonth the ISO day-of-month + * @return the ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate date(int prolepticYear, int month, int dayOfMonth) { + return LocalDate.of(prolepticYear, month, dayOfMonth); + } + + /** + * Obtains an ISO local date from the era, year-of-era and day-of-year fields. + * + * @param era the ISO era, not null + * @param yearOfEra the ISO year-of-era + * @param dayOfYear the ISO day-of-year + * @return the ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); + } + + /** + * Obtains an ISO local date from the proleptic-year and day-of-year fields. + *

    + * This is equivalent to {@link LocalDate#ofYearDay(int, int)}. + * + * @param prolepticYear the ISO proleptic-year + * @param dayOfYear the ISO day-of-year + * @return the ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate dateYearDay(int prolepticYear, int dayOfYear) { + return LocalDate.ofYearDay(prolepticYear, dayOfYear); + } + + //----------------------------------------------------------------------- + /** + * Obtains an ISO local date from another date-time object. + *

    + * This is equivalent to {@link LocalDate#from(TemporalAccessor)}. + * + * @param temporal the date-time object to convert, not null + * @return the ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate date(TemporalAccessor temporal) { + return LocalDate.from(temporal); + } + + /** + * Obtains an ISO local date-time from another date-time object. + *

    + * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}. + * + * @param temporal the date-time object to convert, not null + * @return the ISO local date-time, not null + * @throws DateTimeException if unable to create the date-time + */ + @Override // override with covariant return type + public LocalDateTime localDateTime(TemporalAccessor temporal) { + return LocalDateTime.from(temporal); + } + + /** + * Obtains an ISO zoned date-time from another date-time object. + *

    + * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}. + * + * @param temporal the date-time object to convert, not null + * @return the ISO zoned date-time, not null + * @throws DateTimeException if unable to create the date-time + */ + @Override // override with covariant return type + public ZonedDateTime zonedDateTime(TemporalAccessor temporal) { + return ZonedDateTime.from(temporal); + } + + /** + * Obtains an ISO zoned date-time in this chronology from an {@code Instant}. + *

    + * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}. + * + * @param instant the instant to create the date-time from, not null + * @param zone the time-zone, not null + * @return the zoned date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + return ZonedDateTime.ofInstant(instant, zone); + } + + //----------------------------------------------------------------------- + /** + * Obtains the current ISO local date from the system clock in the default time-zone. + *

    + * This will query the {@link Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current ISO local date using the system clock and default time-zone, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate dateNow() { + return dateNow(Clock.systemDefaultZone()); + } + + /** + * Obtains the current ISO local date from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. + * Specifying the time-zone avoids dependence on the default time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current ISO local date using the system clock, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate dateNow(ZoneId zone) { + return dateNow(Clock.system(zone)); + } + + /** + * Obtains the current ISO local date from the specified clock. + *

    + * This will query the specified clock to obtain the current date - today. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current ISO local date, not null + * @throws DateTimeException if unable to create the date + */ + @Override // override with covariant return type + public LocalDate dateNow(Clock clock) { + Objects.requireNonNull(clock, "clock"); + return date(LocalDate.now(clock)); + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is a leap year, according to the ISO proleptic + * calendar system rules. + *

    + * This method applies the current rules for leap years across the whole time-line. + * In general, a year is a leap year if it is divisible by four without + * remainder. However, years divisible by 100, are not leap years, with + * the exception of years divisible by 400 which are. + *

    + * For example, 1904 is a leap year it is divisible by 4. + * 1900 was not a leap year as it is divisible by 100, however 2000 was a + * leap year as it is divisible by 400. + *

    + * The calculation is proleptic - applying the same rules into the far future and far past. + * This is historically inaccurate, but is correct for the ISO-8601 standard. + * + * @param prolepticYear the ISO proleptic year to check + * @return true if the year is leap, false otherwise + */ + @Override + public boolean isLeapYear(long prolepticYear) { + return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0); + } + + @Override + public int prolepticYear(Era era, int yearOfEra) { + if (era instanceof ISOEra == false) { + throw new DateTimeException("Era must be ISOEra"); + } + return (era == ISOEra.CE ? yearOfEra : 1 - yearOfEra); + } + + @Override + public Era eraOf(int eraValue) { + return ISOEra.of(eraValue); + } + + @Override + public List> eras() { + return Arrays.>asList(ISOEra.values()); + } + + //----------------------------------------------------------------------- + @Override + public ValueRange range(ChronoField field) { + return field.range(); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ISOEra.java b/jdk/src/share/classes/java/time/temporal/ISOEra.java new file mode 100644 index 00000000000..21009f6b183 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ISOEra.java @@ -0,0 +1,204 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import static java.time.temporal.ChronoField.ERA; + +import java.time.DateTimeException; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.util.Locale; + +/** + * An era in the ISO calendar system. + *

    + * The ISO-8601 standard does not define eras. + * A definition has therefore been created with two eras - 'Current era' (CE) for + * years from 0001-01-01 (ISO) and 'Before current era' (BCE) for years before that. + *

    + * Do not use {@code ordinal()} to obtain the numeric representation of {@code ISOEra}. + * Use {@code getValue()} instead. + * + *

    Specification for implementors

    + * This is an immutable and thread-safe enum. + * + * @since 1.8 + */ +enum ISOEra implements Era { + + /** + * The singleton instance for the era BCE, 'Before Current Era'. + * The 'ISO' part of the name emphasizes that this differs from the BCE + * era in the Gregorian calendar system. + * This has the numeric value of {@code 0}. + */ + BCE, + /** + * The singleton instance for the era CE, 'Current Era'. + * The 'ISO' part of the name emphasizes that this differs from the CE + * era in the Gregorian calendar system. + * This has the numeric value of {@code 1}. + */ + CE; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code ISOEra} from an {@code int} value. + *

    + * {@code ISOEra} is an enum representing the ISO eras of BCE/CE. + * This factory allows the enum to be obtained from the {@code int} value. + * + * @param era the BCE/CE value to represent, from 0 (BCE) to 1 (CE) + * @return the era singleton, not null + * @throws DateTimeException if the value is invalid + */ + public static ISOEra of(int era) { + switch (era) { + case 0: + return BCE; + case 1: + return CE; + default: + throw new DateTimeException("Invalid era: " + era); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the numeric era {@code int} value. + *

    + * The era BCE has the value 0, while the era CE has the value 1. + * + * @return the era value, from 0 (BCE) to 1 (CE) + */ + @Override + public int getValue() { + return ordinal(); + } + + @Override + public ISOChrono getChrono() { + return ISOChrono.INSTANCE; + } + + // JDK8 default methods: + //----------------------------------------------------------------------- + @Override + public ChronoLocalDate date(int year, int month, int day) { + return getChrono().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 temporal) { + return temporal.with(ERA, getValue()); + } + + //----------------------------------------------------------------------- + @Override + public String getText(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/ISOFields.java b/jdk/src/share/classes/java/time/temporal/ISOFields.java new file mode 100644 index 00000000000..548d1d5e31b --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ISOFields.java @@ -0,0 +1,564 @@ +/* + * 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) 2011-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 java.time.temporal; + +import static java.time.DayOfWeek.THURSDAY; +import static java.time.DayOfWeek.WEDNESDAY; +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.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.time.DateTimeException; +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeBuilder; + +/** + * Fields and units specific to the ISO-8601 calendar system, + * including quarter-of-year and week-based-year. + *

    + * This class defines fields and units that are specific to the ISO calendar system. + * + *

    Quarter of year

    + * The ISO-8601 standard is based on the standard civic 12 month year. + * This is commonly divided into four quarters, often abbreviated as Q1, Q2, Q3 and Q4. + *

    + * January, February and March are in Q1. + * April, May and June are in Q2. + * July, August and September are in Q3. + * October, November and December are in Q4. + *

    + * The complete date is expressed using three fields: + *

      + *
    • {@link #DAY_OF_QUARTER DAY_OF_QUARTER} - the day within the quarter, from 1 to 90, 91 or 92 + *
    • {@link #QUARTER_OF_YEAR QUARTER_OF_YEAR} - the week within the week-based-year + *
    • {@link ChronoField#YEAR YEAR} - the standard ISO year + *

    + * + *

    Week based years

    + * The ISO-8601 standard was originally intended as a data interchange format, + * defining a string format for dates and times. However, it also defines an + * alternate way of expressing the date, based on the concept of week-based-year. + *

    + * The date is expressed using three fields: + *

      + *
    • {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} - the standard field defining the + * day-of-week from Monday (1) to Sunday (7) + *
    • {@link #WEEK_OF_WEEK_BASED_YEAR} - the week within the week-based-year + *
    • {@link #WEEK_BASED_YEAR WEEK_BASED_YEAR} - the week-based-year + *

    + * The week-based-year itself is defined relative to the standard ISO proleptic year. + * It differs from the standard year in that it always starts on a Monday. + *

    + * The first week of a week-based-year is the first Monday-based week of the standard + * ISO year that has at least 4 days in the new year. + *

      + *
    • If January 1st is Monday then week 1 starts on January 1st + *
    • If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year + *
    • If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year + *
    • If January 1st is Thursday then week 1 starts on December 29th of the previous standard year + *
    • If January 1st is Friday then week 1 starts on January 4th + *
    • If January 1st is Saturday then week 1 starts on January 3rd + *
    • If January 1st is Sunday then week 1 starts on January 2nd + *

    + * There are 52 weeks in most week-based years, however on occasion there are 53 weeks. + *

    + * For example: + *

    + * + * + * + * + * + * + * + * + * + *
    Examples of Week based Years
    DateDay-of-weekField values
    2008-12-28SundayWeek 52 of week-based-year 2008
    2008-12-29MondayWeek 1 of week-based-year 2009
    2008-12-31WednesdayWeek 1 of week-based-year 2009
    2009-01-01ThursdayWeek 1 of week-based-year 2009
    2009-01-04SundayWeek 1 of week-based-year 2009
    2009-01-05MondayWeek 2 of week-based-year 2009
    + * + *

    Specification for implementors

    + *

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ISOFields { + + /** + * The field that represents the day-of-quarter. + *

    + * This field allows the day-of-quarter value to be queried and set. + * The day-of-quarter has values from 1 to 90 in Q1 of a standard year, from 1 to 91 + * in Q1 of a leap year, from 1 to 91 in Q2 and from 1 to 92 in Q3 and Q4. + *

    + * The day-of-quarter can only be calculated if the day-of-year, month-of-year and year + * are available. + *

    + * When setting this field, the value is allowed to be partially lenient, taking any + * value from 1 to 92. If the quarter has less than 92 days, then day 92, and + * potentially day 91, is in the following quarter. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField DAY_OF_QUARTER = Field.DAY_OF_QUARTER; + /** + * The field that represents the quarter-of-year. + *

    + * This field allows the quarter-of-year value to be queried and set. + * The quarter-of-year has values from 1 to 4. + *

    + * The day-of-quarter can only be calculated if the month-of-year is available. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField QUARTER_OF_YEAR = Field.QUARTER_OF_YEAR; + /** + * The field that represents the week-of-week-based-year. + *

    + * This field allows the week of the week-based-year value to be queried and set. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = Field.WEEK_OF_WEEK_BASED_YEAR; + /** + * The field that represents the week-based-year. + *

    + * This field allows the week-based-year value to be queried and set. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalField WEEK_BASED_YEAR = Field.WEEK_BASED_YEAR; + /** + * The unit that represents week-based-years for the purpose of addition and subtraction. + *

    + * This allows a number of week-based-years to be added to, or subtracted from, a date. + * The unit is equal to either 52 or 53 weeks. + * The estimated duration of a week-based-year is the same as that of a standard ISO + * year at {@code 365.2425 Days}. + *

    + * The rules for addition add the number of week-based-years to the existing value + * for the week-based-year field. If the resulting week-based-year only has 52 weeks, + * then the date will be in week 1 of the following week-based-year. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalUnit WEEK_BASED_YEARS = Unit.WEEK_BASED_YEARS; + /** + * Unit that represents the concept of a quarter-year. + * For the ISO calendar system, it is equal to 3 months. + * The estimated duration of a quarter-year is one quarter of {@code 365.2425 Days}. + *

    + * This unit is an immutable and thread-safe singleton. + */ + public static final TemporalUnit QUARTER_YEARS = Unit.QUARTER_YEARS; + + /** + * Restricted constructor. + */ + private ISOFields() { + throw new AssertionError("Not instantiable"); + } + + //----------------------------------------------------------------------- + /** + * Implementation of the field. + */ + private static enum Field implements TemporalField { + DAY_OF_QUARTER { + @Override + public String getName() { + return "DayOfQuarter"; + } + @Override + public TemporalUnit getBaseUnit() { + return DAYS; + } + @Override + public TemporalUnit getRangeUnit() { + return QUARTER_YEARS; + } + @Override + public ValueRange range() { + return ValueRange.of(1, 90, 92); + } + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(DAY_OF_YEAR) && temporal.isSupported(MONTH_OF_YEAR) && + temporal.isSupported(YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE); + } + @Override + public ValueRange doRange(TemporalAccessor temporal) { + if (doIsSupported(temporal) == false) { + throw new DateTimeException("Unsupported field: DayOfQuarter"); + } + long qoy = temporal.getLong(QUARTER_OF_YEAR); + if (qoy == 1) { + long year = temporal.getLong(YEAR); + return (ISOChrono.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 91) : ValueRange.of(1, 90)); + } else if (qoy == 2) { + return ValueRange.of(1, 91); + } else if (qoy == 3 || qoy == 4) { + return ValueRange.of(1, 92); + } // else value not from 1 to 4, so drop through + return range(); + } + @Override + public long doGet(TemporalAccessor temporal) { + if (doIsSupported(temporal) == false) { + throw new DateTimeException("Unsupported field: DayOfQuarter"); + } + int doy = temporal.get(DAY_OF_YEAR); + int moy = temporal.get(MONTH_OF_YEAR); + long year = temporal.getLong(YEAR); + return doy - QUARTER_DAYS[((moy - 1) / 3) + (ISOChrono.INSTANCE.isLeapYear(year) ? 4 : 0)]; + } + @Override + public R doWith(R temporal, long newValue) { + long curValue = doGet(temporal); + range().checkValidValue(newValue, this); + return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue)); + } + }, + QUARTER_OF_YEAR { + @Override + public String getName() { + return "QuarterOfYear"; + } + @Override + public TemporalUnit getBaseUnit() { + return QUARTER_YEARS; + } + @Override + public TemporalUnit getRangeUnit() { + return YEARS; + } + @Override + public ValueRange range() { + return ValueRange.of(1, 4); + } + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(MONTH_OF_YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE); + } + @Override + public long doGet(TemporalAccessor temporal) { + if (doIsSupported(temporal) == false) { + throw new DateTimeException("Unsupported field: DayOfQuarter"); + } + long moy = temporal.getLong(MONTH_OF_YEAR); + return ((moy + 2) / 3); + } + @Override + public R doWith(R temporal, long newValue) { + long curValue = doGet(temporal); + range().checkValidValue(newValue, this); + return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3); + } + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + Long[] values = builder.queryFieldValues(YEAR, QUARTER_OF_YEAR, DAY_OF_QUARTER); + if (values[0] != null && values[1] != null && values[2] != null) { + int y = YEAR.range().checkValidIntValue(values[0], YEAR); + int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(values[1], QUARTER_OF_YEAR); + int doq = DAY_OF_QUARTER.range().checkValidIntValue(values[2], DAY_OF_QUARTER); + LocalDate date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(doq - 1); + builder.addFieldValue(EPOCH_DAY, date.toEpochDay()); + builder.removeFieldValues(QUARTER_OF_YEAR, DAY_OF_QUARTER); + } + return false; + } + }, + WEEK_OF_WEEK_BASED_YEAR { + @Override + public String getName() { + return "WeekOfWeekBasedYear"; + } + @Override + public TemporalUnit getBaseUnit() { + return WEEKS; + } + @Override + public TemporalUnit getRangeUnit() { + return WEEK_BASED_YEARS; + } + @Override + public ValueRange range() { + return ValueRange.of(1, 52, 53); + } + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(EPOCH_DAY); + } + @Override + public ValueRange doRange(TemporalAccessor temporal) { + return getWeekRange(LocalDate.from(temporal)); + } + @Override + public long doGet(TemporalAccessor temporal) { + return getWeek(LocalDate.from(temporal)); + } + @Override + public R doWith(R temporal, long newValue) { + ValueRange.of(1, 53).checkValidValue(newValue, this); + return (R) temporal.plus(Math.subtractExact(newValue, doGet(temporal)), WEEKS); + } + }, + WEEK_BASED_YEAR { + @Override + public String getName() { + return "WeekBasedYear"; + } + @Override + public TemporalUnit getBaseUnit() { + return WEEK_BASED_YEARS; + } + @Override + public TemporalUnit getRangeUnit() { + return FOREVER; + } + @Override + public ValueRange range() { + return YEAR.range(); + } + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(EPOCH_DAY); + } + @Override + public long doGet(TemporalAccessor temporal) { + return getWeekBasedYear(LocalDate.from(temporal)); + } + @Override + public R doWith(R temporal, long newValue) { + int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR); + LocalDate date = LocalDate.from(temporal); + int week = getWeek(date); + date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week); + return (R) date.with(date); + } + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + Long[] values = builder.queryFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK); + if (values[0] != null && values[1] != null && values[2] != null) { + int wby = WEEK_BASED_YEAR.range().checkValidIntValue(values[0], WEEK_BASED_YEAR); + int week = WEEK_OF_WEEK_BASED_YEAR.range().checkValidIntValue(values[1], WEEK_OF_WEEK_BASED_YEAR); + int dow = DAY_OF_WEEK.range().checkValidIntValue(values[2], DAY_OF_WEEK); + LocalDate date = LocalDate.of(wby, 2, 1).with(WEEK_OF_WEEK_BASED_YEAR, week).with(DAY_OF_WEEK, dow); + builder.addFieldValue(EPOCH_DAY, date.toEpochDay()); + builder.removeFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK); + } + return false; + } + }; + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + return range(); + } + + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + return false; + } + + @Override + public String toString() { + return getName(); + } + + //------------------------------------------------------------------------- + private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274}; + + private static ValueRange getWeekRange(LocalDate date) { + int wby = getWeekBasedYear(date); + date = date.withDayOfYear(1).withYear(wby); + // 53 weeks if standard year starts on Thursday, or Wed in a leap year + if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) { + return ValueRange.of(1, 53); + } + return ValueRange.of(1, 52); + } + + private static int getWeek(LocalDate date) { + int dow0 = date.getDayOfWeek().ordinal(); + int doy0 = date.getDayOfYear() - 1; + int doyThu0 = doy0 + (3 - dow0); // adjust to mid-week Thursday (which is 3 indexed from zero) + int alignedWeek = doyThu0 / 7; + int firstThuDoy0 = doyThu0 - (alignedWeek * 7); + int firstMonDoy0 = firstThuDoy0 - 3; + if (firstMonDoy0 < -3) { + firstMonDoy0 += 7; + } + if (doy0 < firstMonDoy0) { + return (int) getWeekRange(date.withDayOfYear(180).minusYears(1)).getMaximum(); + } + int week = ((doy0 - firstMonDoy0) / 7) + 1; + if (week == 53) { + if ((firstMonDoy0 == -3 || (firstMonDoy0 == -2 && date.isLeapYear())) == false) { + week = 1; + } + } + return week; + } + + private static int getWeekBasedYear(LocalDate date) { + int year = date.getYear(); + int doy = date.getDayOfYear(); + if (doy <= 3) { + int dow = date.getDayOfWeek().ordinal(); + if (doy - dow < -2) { + year--; + } + } else if (doy >= 363) { + int dow = date.getDayOfWeek().ordinal(); + doy = doy - 363 - (date.isLeapYear() ? 1 : 0); + if (doy - dow >= 0) { + year++; + } + } + return year; + } + } + + //----------------------------------------------------------------------- + /** + * Implementation of the period unit. + */ + private static enum Unit implements TemporalUnit { + + /** + * Unit that represents the concept of a week-based-year. + */ + WEEK_BASED_YEARS("WeekBasedYears", Duration.ofSeconds(31556952L)), + /** + * Unit that represents the concept of a quarter-year. + */ + QUARTER_YEARS("QuarterYears", Duration.ofSeconds(31556952L / 4)); + + private final String name; + private final Duration duration; + + private Unit(String name, Duration estimatedDuration) { + this.name = name; + this.duration = estimatedDuration; + } + + @Override + public String getName() { + return name; + } + + @Override + public Duration getDuration() { + return duration; + } + + @Override + public boolean isDurationEstimated() { + return true; + } + + @Override + public boolean isSupported(Temporal temporal) { + return temporal.isSupported(EPOCH_DAY); + } + + @Override + public R doPlus(R dateTime, long periodToAdd) { + switch(this) { + case WEEK_BASED_YEARS: + return (R) dateTime.with(WEEK_BASED_YEAR, + Math.addExact(dateTime.get(WEEK_BASED_YEAR), periodToAdd)); + case QUARTER_YEARS: + // no overflow (256 is multiple of 4) + return (R) dateTime.plus(periodToAdd / 256, YEARS) + .plus((periodToAdd % 256) * 3, MONTHS); + default: + throw new IllegalStateException("Unreachable"); + } + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + switch(this) { + case WEEK_BASED_YEARS: + long period = Math.subtractExact(dateTime2.getLong(WEEK_BASED_YEAR), + dateTime1.getLong(WEEK_BASED_YEAR)); + return new SimplePeriod(period, WEEK_BASED_YEARS); + case QUARTER_YEARS: + long period2 = Math.subtractExact(dateTime2.getLong(QUARTER_OF_YEAR), + dateTime1.getLong(QUARTER_OF_YEAR)); + return new SimplePeriod(period2, QUARTER_YEARS); + default: + throw new IllegalStateException("Unreachable"); + } + } + + @Override + public String toString() { + return getName(); + + } + } +} diff --git a/jdk/src/share/classes/java/time/temporal/JulianFields.java b/jdk/src/share/classes/java/time/temporal/JulianFields.java new file mode 100644 index 00000000000..79a9e96bac7 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/JulianFields.java @@ -0,0 +1,305 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; + +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.format.DateTimeBuilder; + +/** + * A set of date fields that provide access to Julian Days. + *

    + * The Julian Day is a standard way of expressing date and time commonly used in the scientific community. + * It is expressed as a decimal number of whole days where days start at midday. + * This class represents variations on Julian Days that count whole days from midnight. + * + *

    Specification for implementors

    + * This is an immutable and thread-safe class. + * + * @since 1.8 + */ +public final class JulianFields { + + /** + * The offset from Julian to EPOCH DAY. + */ + private static final long JULIAN_DAY_OFFSET = 2440588L; + + /** + * Julian Day field. + *

    + * This is an integer-based version of the Julian Day Number. + * Julian Day is a well-known system that represents the count of whole days since day 0, + * which is defined to be January 1, 4713 BCE in the Julian calendar, and -4713-11-24 Gregorian. + * The field has "JulianDay" as 'name', and 'DAYS' as 'baseUnit'. + * The field always refers to the local date-time, ignoring the offset or zone. + *

    + * For date-times, 'JULIAN_DAY.doGet()' assumes the same value from + * midnight until just before the next midnight. + * When 'JULIAN_DAY.doWith()' is applied to a date-time, the time of day portion remains unaltered. + * 'JULIAN_DAY.doWith()' and 'JULIAN_DAY.doGet()' only apply to {@code Temporal} objects that + * can be converted into {@link ChronoField#EPOCH_DAY}. + * A {@link DateTimeException} is thrown for any other type of object. + *

    + *

    Astronomical and Scientific Notes

    + * The standard astronomical definition uses a fraction to indicate the time-of-day, + * thus 3.25 would represent the time 18:00, since days start at midday. + * This implementation uses an integer and days starting at midnight. + * The integer value for the Julian Day Number is the astronomical Julian Day value at midday + * of the date in question. + * This amounts to the astronomical Julian Day, rounded to an integer {@code JDN = floor(JD + 0.5)}. + *

    + *

    +     *  | ISO date          |  Julian Day Number | Astronomical Julian Day |
    +     *  | 1970-01-01T00:00  |         2,440,588  |         2,440,587.5     |
    +     *  | 1970-01-01T06:00  |         2,440,588  |         2,440,587.75    |
    +     *  | 1970-01-01T12:00  |         2,440,588  |         2,440,588.0     |
    +     *  | 1970-01-01T18:00  |         2,440,588  |         2,440,588.25    |
    +     *  | 1970-01-02T00:00  |         2,440,589  |         2,440,588.5     |
    +     *  | 1970-01-02T06:00  |         2,440,589  |         2,440,588.75    |
    +     *  | 1970-01-02T12:00  |         2,440,589  |         2,440,589.0     |
    +     * 
    + *

    + * Julian Days are sometimes taken to imply Universal Time or UTC, but this + * implementation always uses the Julian Day number for the local date, + * regardless of the offset or time-zone. + */ + public static final TemporalField JULIAN_DAY = new Field("JulianDay", DAYS, FOREVER, JULIAN_DAY_OFFSET); + + /** + * Modified Julian Day field. + *

    + * This is an integer-based version of the Modified Julian Day Number. + * Modified Julian Day (MJD) is a well-known system that counts days continuously. + * It is defined relative to astronomical Julian Day as {@code MJD = JD - 2400000.5}. + * Each Modified Julian Day runs from midnight to midnight. + * The field always refers to the local date-time, ignoring the offset or zone. + *

    + * For date-times, 'MODIFIED_JULIAN_DAY.doGet()' assumes the same value from + * midnight until just before the next midnight. + * When 'MODIFIED_JULIAN_DAY.doWith()' is applied to a date-time, the time of day portion remains unaltered. + * 'MODIFIED_JULIAN_DAY.doWith()' and 'MODIFIED_JULIAN_DAY.doGet()' only apply to {@code Temporal} objects + * that can be converted into {@link ChronoField#EPOCH_DAY}. + * A {@link DateTimeException} is thrown for any other type of object. + *

    + * This implementation is an integer version of MJD with the decimal part rounded to floor. + *

    + *

    Astronomical and Scientific Notes

    + *
    +     *  | ISO date          | Modified Julian Day |      Decimal MJD |
    +     *  | 1970-01-01T00:00  |             40,587  |       40,587.0   |
    +     *  | 1970-01-01T06:00  |             40,587  |       40,587.25  |
    +     *  | 1970-01-01T12:00  |             40,587  |       40,587.5   |
    +     *  | 1970-01-01T18:00  |             40,587  |       40,587.75  |
    +     *  | 1970-01-02T00:00  |             40,588  |       40,588.0   |
    +     *  | 1970-01-02T06:00  |             40,588  |       40,588.25  |
    +     *  | 1970-01-02T12:00  |             40,588  |       40,588.5   |
    +     * 
    + *

    + * Modified Julian Days are sometimes taken to imply Universal Time or UTC, but this + * implementation always uses the Modified Julian Day for the local date, + * regardless of the offset or time-zone. + */ + public static final TemporalField MODIFIED_JULIAN_DAY = new Field("ModifiedJulianDay", DAYS, FOREVER, 40587L); + + /** + * Rata Die field. + *

    + * Rata Die counts whole days continuously starting day 1 at midnight at the beginning of 0001-01-01 (ISO). + * The field always refers to the local date-time, ignoring the offset or zone. + *

    + * For date-times, 'RATA_DIE.doGet()' assumes the same value from + * midnight until just before the next midnight. + * When 'RATA_DIE.doWith()' is applied to a date-time, the time of day portion remains unaltered. + * 'MODIFIED_JULIAN_DAY.doWith()' and 'RATA_DIE.doGet()' only apply to {@code Temporal} objects + * that can be converted into {@link ChronoField#EPOCH_DAY}. + * A {@link DateTimeException} is thrown for any other type of object. + */ + public static final TemporalField RATA_DIE = new Field("RataDie", DAYS, FOREVER, 719163L); + + /** + * Restricted constructor. + */ + private JulianFields() { + throw new AssertionError("Not instantiable"); + } + + /** + * implementation of JulianFields. Each instance is a singleton. + */ + private static class Field implements TemporalField, Serializable { + + private static final long serialVersionUID = -7501623920830201812L; + + private final String name; + private final transient TemporalUnit baseUnit; + private final transient TemporalUnit rangeUnit; + private final transient ValueRange range; + private final transient long offset; + + private Field(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, long offset) { + this.name = name; + this.baseUnit = baseUnit; + this.rangeUnit = rangeUnit; + this.range = ValueRange.of(-365243219162L + offset, 365241780471L + offset); + this.offset = offset; + } + + + /** + * Resolve the object from the stream to the appropriate singleton. + * @return one of the singleton objects {@link #JULIAN_DAY}, + * {@link #MODIFIED_JULIAN_DAY}, or {@link #RATA_DIE}. + * @throws InvalidObjectException if the object in the stream is not one of the singletons. + */ + private Object readResolve() throws InvalidObjectException { + if (JULIAN_DAY.getName().equals(name)) { + return JULIAN_DAY; + } else if (MODIFIED_JULIAN_DAY.getName().equals(name)) { + return MODIFIED_JULIAN_DAY; + } else if (RATA_DIE.getName().equals(name)) { + return RATA_DIE; + } else { + throw new InvalidObjectException("Not one of the singletons"); + } + } + + //----------------------------------------------------------------------- + @Override + public String getName() { + return name; + } + + @Override + public TemporalUnit getBaseUnit() { + return baseUnit; + } + + @Override + public TemporalUnit getRangeUnit() { + return rangeUnit; + } + + @Override + public ValueRange range() { + return range; + } + + //----------------------------------------------------------------------- + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return temporal.isSupported(EPOCH_DAY); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + if (doIsSupported(temporal) == false) { + throw new DateTimeException("Unsupported field: " + this); + } + return range(); + } + + @Override + public long doGet(TemporalAccessor temporal) { + return temporal.getLong(EPOCH_DAY) + offset; + } + + @Override + public R doWith(R temporal, long newValue) { + if (range().isValidValue(newValue) == false) { + throw new DateTimeException("Invalid value: " + name + " " + newValue); + } + return (R) temporal.with(EPOCH_DAY, Math.subtractExact(newValue, offset)); + } + + //----------------------------------------------------------------------- + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + boolean changed = false; + changed = resolve0(JULIAN_DAY, builder, changed); + changed = resolve0(MODIFIED_JULIAN_DAY, builder, changed); + changed = resolve0(RATA_DIE, builder, changed); + return changed; + } + + private boolean resolve0(TemporalField field, DateTimeBuilder builder, boolean changed) { + if (builder.containsFieldValue(field)) { + builder.addCalendrical(LocalDate.ofEpochDay(Math.subtractExact(builder.getFieldValue(JULIAN_DAY), JULIAN_DAY_OFFSET))); + builder.removeFieldValue(JULIAN_DAY); + changed = true; + } + return changed; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + return getName(); + } + } +} diff --git a/jdk/src/share/classes/java/time/temporal/MonthDay.java b/jdk/src/share/classes/java/time/temporal/MonthDay.java new file mode 100644 index 00000000000..7707cd099a5 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/MonthDay.java @@ -0,0 +1,755 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.util.Objects; + +/** + * A month-day in the ISO-8601 calendar system, such as {@code --12-03}. + *

    + * {@code MonthDay} is an immutable date-time object that represents the combination + * of a year and month. Any field that can be derived from a month and day, such as + * quarter-of-year, can be obtained. + *

    + * This class does not store or represent a year, time or time-zone. + * For example, the value "December 3rd" can be stored in a {@code MonthDay}. + *

    + * Since a {@code MonthDay} does not possess a year, the leap day of + * February 29th is considered valid. + *

    + * This class implements {@link TemporalAccessor} rather than {@link Temporal}. + * This is because it is not possible to define whether February 29th is valid or not + * without external information, preventing the implementation of plus/minus. + * Related to this, {@code MonthDay} only provides access to query and set the fields + * {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH}. + *

    + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * For most applications written today, the ISO-8601 rules are entirely suitable. + * However, any application that makes use of historical dates, and requires them + * to be accurate will find the ISO-8601 approach unsuitable. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class MonthDay + implements TemporalAccessor, TemporalAdjuster, Comparable, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -939150713474957432L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendLiteral("--") + .appendValue(MONTH_OF_YEAR, 2) + .appendLiteral('-') + .appendValue(DAY_OF_MONTH, 2) + .toFormatter(); + + /** + * The month-of-year, not null. + */ + private final int month; + /** + * The day-of-month. + */ + private final int day; + + //----------------------------------------------------------------------- + /** + * Obtains the current month-day from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current month-day. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current month-day using the system clock and default time-zone, not null + */ + public static MonthDay now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current month-day from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current month-day. + * Specifying the time-zone avoids dependence on the default time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current month-day using the system clock, not null + */ + public static MonthDay now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current month-day from the specified clock. + *

    + * This will query the specified clock to obtain the current month-day. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current month-day, not null + */ + public static MonthDay now(Clock clock) { + final LocalDate now = LocalDate.now(clock); // called once + return MonthDay.of(now.getMonth(), now.getDayOfMonth()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay}. + *

    + * The day-of-month must be valid for the month within a leap year. + * Hence, for February, day 29 is valid. + *

    + * For example, passing in April and day 31 will throw an exception, as + * there can never be April 31st in any year. By contrast, passing in + * February 29th is permitted, as that month-day can sometimes be valid. + * + * @param month the month-of-year to represent, not null + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the month-day, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month + */ + public static MonthDay of(Month month, int dayOfMonth) { + Objects.requireNonNull(month, "month"); + DAY_OF_MONTH.checkValidValue(dayOfMonth); + if (dayOfMonth > month.maxLength()) { + throw new DateTimeException("Illegal value for DayOfMonth field, value " + dayOfMonth + + " is not valid for month " + month.name()); + } + return new MonthDay(month.getValue(), dayOfMonth); + } + + /** + * Obtains an instance of {@code MonthDay}. + *

    + * The day-of-month must be valid for the month within a leap year. + * Hence, for month 2 (February), day 29 is valid. + *

    + * For example, passing in month 4 (April) and day 31 will throw an exception, as + * there can never be April 31st in any year. By contrast, passing in + * February 29th is permitted, as that month-day can sometimes be valid. + * + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the month-day, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month + */ + public static MonthDay of(int month, int dayOfMonth) { + return of(Month.of(month), dayOfMonth); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code MonthDay}. + *

    + * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and + * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields. + * The extraction is only permitted if the date-time has an ISO chronology. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code MonthDay::from}. + * + * @param temporal the temporal object to convert, not null + * @return the month-day, not null + * @throws DateTimeException if unable to convert to a {@code MonthDay} + */ + public static MonthDay from(TemporalAccessor temporal) { + if (temporal instanceof MonthDay) { + return (MonthDay) temporal; + } + try { + if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) { + temporal = LocalDate.from(temporal); + } + return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH)); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay} from a text string such as {@code --12-03}. + *

    + * The string must represent a valid month-day. + * The format is {@code --MM-dd}. + * + * @param text the text to parse such as "--12-03", not null + * @return the parsed month-day, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static MonthDay parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code MonthDay} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a month-day. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed month-day, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, MonthDay::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor, previously validated. + * + * @param month the month-of-year to represent, validated from 1 to 12 + * @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31 + */ + private MonthDay(int month, int dayOfMonth) { + this.month = month; + this.day = dayOfMonth; + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this month-day can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * The supported fields are: + *

      + *
    • {@code MONTH_OF_YEAR} + *
    • {@code YEAR} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this month-day, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == MONTH_OF_YEAR || field == DAY_OF_MONTH; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This month-day is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field == MONTH_OF_YEAR) { + return field.range(); + } else if (field == DAY_OF_MONTH) { + return ValueRange.of(1, getMonth().minLength(), getMonth().maxLength()); + } + return TemporalAccessor.super.range(field); + } + + /** + * Gets the value of the specified field from this month-day as an {@code int}. + *

    + * This queries this month-day for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this month-day. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this month-day as a {@code long}. + *

    + * This queries this month-day for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this month-day. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + // alignedDOW and alignedWOM not supported because they cannot be set in with() + case DAY_OF_MONTH: return day; + case MONTH_OF_YEAR: return month; + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the month-of-year field using the {@code Month} enum. + *

    + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + */ + public Month getMonth() { + return Month.of(month); + } + + /** + * Gets the day-of-month field. + *

    + * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return day; + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is valid for this month-day. + *

    + * This method checks whether this month and day and the input year form + * a valid date. This can only return false for February 29th. + * + * @param year the year to validate, an out of range value returns false + * @return true if the year is valid for this month-day + * @see Year#isValidMonthDay(MonthDay) + */ + public boolean isValidYear(int year) { + return (day == 29 && month == 2 && Year.isLeap(year) == false) == false; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code MonthDay} with the month-of-year altered. + *

    + * This returns a month-day with the specified month. + * If the day-of-month is invalid for the specified month, the day will + * be adjusted to the last valid day-of-month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the returned month-day, from 1 (January) to 12 (December) + * @return a {@code MonthDay} based on this month-day with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public MonthDay withMonth(int month) { + return with(Month.of(month)); + } + + /** + * Returns a copy of this {@code MonthDay} with the month-of-year altered. + *

    + * This returns a month-day with the specified month. + * If the day-of-month is invalid for the specified month, the day will + * be adjusted to the last valid day-of-month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the returned month-day, not null + * @return a {@code MonthDay} based on this month-day with the requested month, not null + */ + public MonthDay with(Month month) { + Objects.requireNonNull(month, "month"); + if (month.getValue() == this.month) { + return this; + } + int day = Math.min(this.day, month.maxLength()); + return new MonthDay(month.getValue(), day); + } + + /** + * Returns a copy of this {@code MonthDay} with the day-of-month altered. + *

    + * This returns a month-day with the specified day-of-month. + * If the day-of-month is invalid for the month, an exception is thrown. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31 + * @return a {@code MonthDay} based on this month-day with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid + * @throws DateTimeException if the day-of-month is invalid for the month + */ + public MonthDay withDayOfMonth(int dayOfMonth) { + if (dayOfMonth == this.day) { + return this; + } + return of(month, dayOfMonth); + } + + //----------------------------------------------------------------------- + /** + * Queries this month-day using the specified query. + *

    + * This queries this month-day using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) ISOChrono.INSTANCE; + } + return TemporalAccessor.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this month-day. + *

    + * This returns a temporal object of the same observable type as the input + * with the month and day-of-month changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#MONTH_OF_YEAR} and + * {@link ChronoField#DAY_OF_MONTH} as the fields. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisMonthDay.adjustInto(temporal);
    +     *   temporal = temporal.with(thisMonthDay);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + temporal = temporal.with(MONTH_OF_YEAR, month); + return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day)); + } + + //----------------------------------------------------------------------- + /** + * Returns a date formed from this month-day at the specified year. + *

    + * This combines this month-day and the specified year to form a {@code LocalDate}. + * A month-day of February 29th will be adjusted to February 28th in the resulting + * date if the year is not a leap year. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param year the year to use, from MIN_YEAR to MAX_YEAR + * @return the local date formed from this month-day and the specified year, not null + * @see Year#atMonthDay(MonthDay) + */ + public LocalDate atYear(int year) { + return LocalDate.of(year, month, isValidYear(year) ? day : 28); + } + + //----------------------------------------------------------------------- + /** + * Compares this month-day to another month-day. + *

    + * The comparison is based first on value of the month, then on the value of the day. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other month-day to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(MonthDay other) { + int cmp = (month - other.month); + if (cmp == 0) { + cmp = (day - other.day); + } + return cmp; + } + + /** + * Is this month-day after the specified month-day. + * + * @param other the other month-day to compare to, not null + * @return true if this is after the specified month-day + */ + public boolean isAfter(MonthDay other) { + return compareTo(other) > 0; + } + + /** + * Is this month-day before the specified month-day. + * + * @param other the other month-day to compare to, not null + * @return true if this point is before the specified month-day + */ + public boolean isBefore(MonthDay other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Checks if this month-day is equal to another month-day. + *

    + * The comparison is based on the time-line position of the month-day within a year. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other month-day + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MonthDay) { + MonthDay other = (MonthDay) obj; + return month == other.month && day == other.day; + } + return false; + } + + /** + * A hash code for this month-day. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return (month << 6) + day; + } + + //----------------------------------------------------------------------- + /** + * Outputs this month-day as a {@code String}, such as {@code --12-03}. + *

    + * The output will be in the format {@code --MM-dd}: + * + * @return a string representation of this month-day, not null + */ + @Override + public String toString() { + return new StringBuilder(10).append("--") + .append(month < 10 ? "0" : "").append(month) + .append(day < 10 ? "-0" : "-").append(day) + .toString(); + } + + /** + * Outputs this month-day as a {@code String} using the formatter. + *

    + * This month-day will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted month-day string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(6);  // identifies this as a Year
    +     *  out.writeByte(month);
    +     *  out.writeByte(day);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.MONTH_DAY_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeByte(month); + out.writeByte(day); + } + + static MonthDay readExternal(DataInput in) throws IOException { + byte month = in.readByte(); + byte day = in.readByte(); + return MonthDay.of(month, day); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/OffsetDate.java b/jdk/src/share/classes/java/time/temporal/OffsetDate.java new file mode 100644 index 00000000000..2503de927bd --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/OffsetDate.java @@ -0,0 +1,1351 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoLocalDateTimeImpl.SECONDS_PER_DAY; +import static java.time.temporal.ChronoUnit.DAYS; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Month; +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.zone.ZoneRules; +import java.util.Objects; + +/** + * A date with an offset from UTC/Greenwich in the ISO-8601 calendar system, + * such as {@code 2007-12-03+01:00}. + *

    + * {@code OffsetDate} is an immutable date-time object that represents a date, often viewed + * as year-month-day-offset. This object can also access other date fields such as + * day-of-year, day-of-week and week-of-year. + *

    + * This class does not store or represent a time. + * For example, the value "2nd October 2007 +02:00" can be stored + * in an {@code OffsetDate}. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class OffsetDate + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The minimum supported {@code OffsetDate}, '-999999999-01-01+18:00'. + * This is the minimum local date in the maximum offset + * (larger offsets are earlier on the time-line). + * This combines {@link LocalDate#MIN} and {@link ZoneOffset#MAX}. + * This could be used by an application as a "far past" date. + */ + public static final OffsetDate MIN = LocalDate.MIN.atOffset(ZoneOffset.MAX); + /** + * The maximum supported {@code OffsetDate}, '+999999999-12-31-18:00'. + * This is the maximum local date in the minimum offset + * (larger negative offsets are later on the time-line). + * This combines {@link LocalDate#MAX} and {@link ZoneOffset#MIN}. + * This could be used by an application as a "far future" date. + */ + public static final OffsetDate MAX = LocalDate.MAX.atOffset(ZoneOffset.MIN); + + /** + * Serialization version. + */ + private static final long serialVersionUID = -4382054179074397774L; + + /** + * The local date. + */ + private final LocalDate date; + /** + * The offset from UTC/Greenwich. + */ + private final ZoneOffset offset; + + //----------------------------------------------------------------------- + /** + * Obtains the current date from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current date using the system clock, not null + */ + public static OffsetDate now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current date from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current date. + * Specifying the time-zone avoids dependence on the default time-zone. + * The offset will be calculated from the specified time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current date using the system clock, not null + */ + public static OffsetDate now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current date from the specified clock. + *

    + * This will query the specified clock to obtain the current date - today. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date, not null + */ + public static OffsetDate now(Clock clock) { + Objects.requireNonNull(clock, "clock"); + final Instant now = clock.instant(); // called once + return ofInstant(now, clock.getZone().getRules().getOffset(now)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a local date and an offset. + * + * @param date the local date, not null + * @param offset the zone offset, not null + * @return the offset date, not null + */ + public static OffsetDate of(LocalDate date, ZoneOffset offset) { + return new OffsetDate(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from an {@code Instant} and zone ID. + *

    + * This creates an offset date with the same instant as midnight at the + * start of day of the instant specified. + * Finding the offset from UTC/Greenwich is simple as there is only one valid + * offset for each instant. + * + * @param instant the instant to create the time from, not null + * @param zone the time-zone, which may be an offset, not null + * @return the offset time, not null + */ + public static OffsetDate ofInstant(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + long epochSec = instant.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later + long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY); + LocalDate date = LocalDate.ofEpochDay(epochDay); + return new OffsetDate(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code OffsetDate}. + *

    + * The conversion extracts and combines {@code LocalDate} and {@code ZoneOffset}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code OffsetDate::from}. + * + * @param temporal the temporal object to convert, not null + * @return the offset date, not null + * @throws DateTimeException if unable to convert to an {@code OffsetDate} + */ + public static OffsetDate from(TemporalAccessor temporal) { + if (temporal instanceof OffsetDate) { + return (OffsetDate) temporal; + } + try { + LocalDate date = LocalDate.from(temporal); + ZoneOffset offset = ZoneOffset.from(temporal); + return new OffsetDate(date, offset); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain OffsetDate from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDate} from a text string such as {@code 2007-12-03+01:00}. + *

    + * The string must represent a valid date and is parsed using + * {@link java.time.format.DateTimeFormatters#isoOffsetDate()}. + * + * @param text the text to parse such as "2007-12-03+01:00", not null + * @return the parsed offset date, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDate parse(CharSequence text) { + return parse(text, DateTimeFormatters.isoOffsetDate()); + } + + /** + * Obtains an instance of {@code OffsetDate} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a date. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed offset date, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDate parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, OffsetDate::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param date the local date, not null + * @param offset the zone offset, not null + */ + private OffsetDate(LocalDate date, ZoneOffset offset) { + this.date = Objects.requireNonNull(date, "date"); + this.offset = Objects.requireNonNull(offset, "offset"); + } + + /** + * Returns a new date based on this one, returning {@code this} where possible. + * + * @param date the date to create with, not null + * @param offset the zone offset to create with, not null + */ + private OffsetDate with(LocalDate date, ZoneOffset offset) { + if (this.date == date && this.offset.equals(offset)) { + return this; + } + return new OffsetDate(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this date can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * The supported fields are: + *

      + *
    • {@code DAY_OF_WEEK} + *
    • {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} + *
    • {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} + *
    • {@code DAY_OF_MONTH} + *
    • {@code DAY_OF_YEAR} + *
    • {@code EPOCH_DAY} + *
    • {@code ALIGNED_WEEK_OF_MONTH} + *
    • {@code ALIGNED_WEEK_OF_YEAR} + *
    • {@code MONTH_OF_YEAR} + *
    • {@code EPOCH_MONTH} + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    • {@code OFFSET_SECONDS} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this date, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return ((ChronoField) field).isDateField() || field == OFFSET_SECONDS; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This date is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return field.range(); + } + return date.range(field); + } + return field.doRange(this); + } + + /** + * Gets the value of the specified field from this date as an {@code int}. + *

    + * This queries this date for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date, except {@code EPOCH_DAY} and {@code EPOCH_MONTH} + * which are too large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this date as a {@code long}. + *

    + * This queries this date for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return getOffset().getTotalSeconds(); + } + return date.getLong(field); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the zone offset, such as '+01:00'. + *

    + * This is the offset of the local date from UTC/Greenwich. + * + * @return the zone offset, not null + */ + public ZoneOffset getOffset() { + return offset; + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified offset. + *

    + * This method returns an object with the same {@code LocalDate} and the specified {@code ZoneOffset}. + * No calculation is needed or performed. + * For example, if this time represents {@code 2007-12-03+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03+03:00}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDate} based on this date with the requested offset, not null + */ + public OffsetDate withOffset(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + return with(date, offset); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDate} part of this date-time. + *

    + * This returns a {@code LocalDate} with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public LocalDate getDate() { + return date; + } + + //----------------------------------------------------------------------- + /** + * Gets the year field. + *

    + * This method returns the primitive {@code int} value for the year. + *

    + * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return date.getYear(); + } + + /** + * Gets the month-of-year field from 1 to 12. + *

    + * This method returns the month as an {@code int} from 1 to 12. + * Application code is frequently clearer if the enum {@link Month} + * is used by calling {@link #getMonth()}. + * + * @return the month-of-year, from 1 to 12 + * @see #getMonth() + */ + public int getMonthValue() { + return date.getMonthValue(); + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + *

    + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + * @see #getMonthValue() + */ + public Month getMonth() { + return date.getMonth(); + } + + /** + * Gets the day-of-month field. + *

    + * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return date.getDayOfMonth(); + } + + /** + * Gets the day-of-year field. + *

    + * This method returns the primitive {@code int} value for the day-of-year. + * + * @return the day-of-year, from 1 to 365, or 366 in a leap year + */ + public int getDayOfYear() { + return date.getDayOfYear(); + } + + /** + * Gets the day-of-week field, which is an enum {@code DayOfWeek}. + *

    + * This method returns the enum {@link java.time.DayOfWeek} for the day-of-week. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link java.time.DayOfWeek#getValue() int value}. + *

    + * Additional information can be obtained from the {@code DayOfWeek}. + * This includes textual names of the values. + * + * @return the day-of-week, not null + */ + public DayOfWeek getDayOfWeek() { + return date.getDayOfWeek(); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this date. + *

    + * This returns a new {@code OffsetDate}, based on this one, with the date adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

    + * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the date to the last day of the month. + * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}. + * These include finding the "last day of the month" and "next Wednesday". + * Key date-time classes also implement the {@code TemporalAdjuster} interface, + * such as {@link Month} and {@link java.time.temporal.MonthDay MonthDay}. + * The adjuster is responsible for handling special cases, such as the varying + * lengths of month and leap years. + *

    + * For example this code returns a date on the last day of July: + *

    +     *  import static java.time.Month.*;
    +     *  import static java.time.temporal.Adjusters.*;
    +     *
    +     *  result = offsetDate.with(JULY).with(lastDayOfMonth());
    +     * 
    + *

    + * The classes {@link LocalDate} and {@link ZoneOffset} implement {@code TemporalAdjuster}, + * thus this method can be used to change the date or offset: + *

    +     *  result = offsetDate.with(date);
    +     *  result = offsetDate.with(offset);
    +     * 
    + *

    + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return an {@code OffsetDate} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate with(TemporalAdjuster adjuster) { + // optimizations + if (adjuster instanceof LocalDate) { + return with((LocalDate) adjuster, offset); + } else if (adjuster instanceof ZoneOffset) { + return with(date, (ZoneOffset) adjuster); + } else if (adjuster instanceof OffsetDate) { + return (OffsetDate) adjuster; + } + return (OffsetDate) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this date with the specified field set to a new value. + *

    + * This returns a new {@code OffsetDate}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year, month or day-of-month. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

    + * In some cases, changing the specified field can cause the resulting date to become invalid, + * such as changing the month from 31st January to February would make the day-of-month invalid. + * In cases like this, the field is responsible for resolving the date. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + *

    + * If the field is a {@link ChronoField} then the adjustment is implemented here. + *

    + * The {@code OFFSET_SECONDS} field will return a date with the specified offset. + * The local date is unaltered. If the new offset value is outside the valid range + * then a {@code DateTimeException} will be thrown. + *

    + * The other {@link #isSupported(TemporalField) supported fields} will behave as per + * the matching method on {@link LocalDate#with(TemporalField, long)} LocalDate}. + * In this case, the offset is not part of the calculation and will be unchanged. + *

    + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an {@code OffsetDate} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + ChronoField f = (ChronoField) field; + return with(date, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); + } + return with(date.with(field, newValue), offset); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR + * @return an {@code OffsetDate} based on this date with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public OffsetDate withYear(int year) { + return with(date.withYear(year), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the month-of-year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the result, from 1 (January) to 12 (December) + * @return an {@code OffsetDate} based on this date with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public OffsetDate withMonth(int month) { + return with(date.withMonth(month), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the day-of-month altered. + * If the resulting date is invalid, an exception is thrown. + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31 + * @return an {@code OffsetDate} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public OffsetDate withDayOfMonth(int dayOfMonth) { + return with(date.withDayOfMonth(dayOfMonth), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the day-of-year altered. + * If the resulting date is invalid, an exception is thrown. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366 + * @return an {@code OffsetDate} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-year value is invalid + * @throws DateTimeException if the day-of-year is invalid for the year + */ + public OffsetDate withDayOfYear(int dayOfYear) { + return with(date.withDayOfYear(dayOfYear), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

    + * This method returns a new date based on this date with the specified period added. + * The adder is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #plus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adder the adder to use, not null + * @return an {@code OffsetDate} based on this date with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate plus(TemporalAdder adder) { + return (OffsetDate) adder.addTo(this); + } + + /** + * Returns a copy of this date with the specified period added. + *

    + * This method returns a new date based on this date with the specified period added. + * This can be used to add any period that is defined by a unit, for example to add years, months or days. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the period to add, not null + * @return an {@code OffsetDate} based on this date with the specified period added, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + @Override + public OffsetDate plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(date.plus(amountToAdd, unit), offset); + } + return unit.doPlus(this, amountToAdd); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the specified period in years added. + *

    + * This method adds the specified amount to the years field in three steps: + *

      + *
    1. Add the input years to the year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2008-02-29 (leap year) plus one year would result in the + * invalid date 2009-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2009-02-28, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param years the years to add, may be negative + * @return an {@code OffsetDate} based on this date with the years added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusYears(long years) { + return with(date.plusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified period in months added. + *

    + * This method adds the specified amount to the months field in three steps: + *

      + *
    1. Add the input months to the month-of-year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2007-03-31 plus one month would result in the invalid date + * 2007-04-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-04-30, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param months the months to add, may be negative + * @return an {@code OffsetDate} based on this date with the months added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusMonths(long months) { + return with(date.plusMonths(months), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified period in weeks added. + *

    + * This method adds the specified amount in weeks to the days field incrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 plus one week would result in 2009-01-07. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to add, may be negative + * @return an {@code OffsetDate} based on this date with the weeks added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusWeeks(long weeks) { + return with(date.plusWeeks(weeks), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified period in days added. + *

    + * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 plus one day would result in 2009-01-01. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return an {@code OffsetDate} based on this date with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate plusDays(long days) { + return with(date.plusDays(days), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period subtracted. + *

    + * This method returns a new date based on this date with the specified period subtracted. + * The subtractor is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #minus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param subtractor the subtractor to use, not null + * @return an {@code OffsetDate} based on this date with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDate minus(TemporalSubtractor subtractor) { + return (OffsetDate) subtractor.subtractFrom(this); + } + + /** + * Returns a copy of this date with the specified period subtracted. + *

    + * This method returns a new date based on this date with the specified period subtracted. + * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the period to subtract, not null + * @return an {@code OffsetDate} based on this date with the specified period subtracted, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + @Override + public OffsetDate minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDate} with the specified period in years subtracted. + *

    + * This method subtracts the specified amount from the years field in three steps: + *

      + *
    1. Subtract the input years to the year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2008-02-29 (leap year) minus one year would result in the + * invalid date 2007-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2007-02-28, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param years the years to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusYears(long years) { + return with(date.minusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified period in months subtracted. + *

    + * This method subtracts the specified amount from the months field in three steps: + *

      + *
    1. Subtract the input months to the month-of-year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2007-03-31 minus one month would result in the invalid date + * 2007-02-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-02-28, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param months the months to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusMonths(long months) { + return with(date.minusMonths(months), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified period in weeks subtracted. + *

    + * This method subtracts the specified amount in weeks from the days field decrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2009-01-07 minus one week would result in 2008-12-31. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the weeks subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusWeeks(long weeks) { + return with(date.minusWeeks(weeks), offset); + } + + /** + * Returns a copy of this {@code OffsetDate} with the specified number of days subtracted. + *

    + * This method subtracts the specified amount from the days field decrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2009-01-01 minus one day would result in 2008-12-31. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param days the days to subtract, may be negative + * @return an {@code OffsetDate} based on this date with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDate minusDays(long days) { + return with(date.minusDays(days), offset); + } + + //----------------------------------------------------------------------- + /** + * Queries this date using the specified query. + *

    + * This queries this date using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) ISOChrono.INSTANCE; + } else if (query == Queries.precision()) { + return (R) DAYS; + } else if (query == Queries.offset() || query == Queries.zone()) { + return (R) getOffset(); + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have the same offset and date + * as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the offset and date changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#OFFSET_SECONDS} and + * {@link ChronoField#EPOCH_DAY} as the fields. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisOffsetDate.adjustInto(temporal);
    +     *   temporal = temporal.with(thisOffsetDate);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + return temporal + .with(OFFSET_SECONDS, getOffset().getTotalSeconds()) + .with(EPOCH_DAY, getDate().toEpochDay()); + } + + /** + * Calculates the period between this date and another date in + * terms of the specified unit. + *

    + * This calculates the period between two dates in terms of a single unit. + * The start and end points are {@code this} and the specified date. + * The result will be negative if the end is before the start. + * For example, the period in days between two dates can be calculated + * using {@code startDate.periodUntil(endDate, DAYS)}. + *

    + * The {@code Temporal} passed to this method must be an {@code OffsetDate}. + * If the offset differs between the two times, then the specified + * end time is normalized to have the same offset as this time. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two dates. + * For example, the period in months between 2012-06-15Z and 2012-08-14Z + * will only be one month as it is one day short of two months. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, MONTHS);   // this method
    +     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS}, + * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} + * are supported. Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endDate the end date, which must be an {@code OffsetDate}, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this date and the end date + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long periodUntil(Temporal endDate, TemporalUnit unit) { + if (endDate instanceof OffsetDate == false) { + Objects.requireNonNull(endDate, "endDate"); + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + if (unit instanceof ChronoUnit) { + OffsetDate end = (OffsetDate) endDate; + long offsetDiff = end.offset.getTotalSeconds() - offset.getTotalSeconds(); + LocalDate endLocal = end.date.plusDays(Math.floorDiv(-offsetDiff, SECONDS_PER_DAY)); + return date.periodUntil(endLocal, unit); + } + return unit.between(this, endDate).getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns an offset date-time formed from this date at the specified time. + *

    + * This combines this date with the specified time to form an {@code OffsetDateTime}. + * All possible combinations of date and time are valid. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param time the time to combine with, not null + * @return the offset date-time formed from this date and the specified time, not null + */ + public OffsetDateTime atTime(LocalTime time) { + return OffsetDateTime.of(date, time, offset); + } + + //----------------------------------------------------------------------- + /** + * Converts this date to midnight at the start of day in epoch seconds. + * + * @return the epoch seconds value + */ + private long toEpochSecond() { + long epochDay = date.toEpochDay(); + long secs = epochDay * SECONDS_PER_DAY; + return secs - offset.getTotalSeconds(); + } + + //----------------------------------------------------------------------- + /** + * Compares this {@code OffsetDate} to another date. + *

    + * The comparison is based first on the UTC equivalent instant, then on the local date. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * For example, the following is the comparator order: + *

      + *
    1. 2008-06-29-11:00
    2. + *
    3. 2008-06-29-12:00
    4. + *
    5. 2008-06-30+12:00
    6. + *
    7. 2008-06-29-13:00
    8. + *
    + * Values #2 and #3 represent the same instant on the time-line. + * When two values represent the same instant, the local date is compared + * to distinguish them. This step is needed to make the ordering + * consistent with {@code equals()}. + *

    + * To compare the underlying local date of two {@code TemporalAccessor} instances, + * use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(OffsetDate other) { + if (offset.equals(other.offset)) { + return date.compareTo(other.date); + } + int compare = Long.compare(toEpochSecond(), other.toEpochSecond()); + if (compare == 0) { + compare = date.compareTo(other.date); + } + return compare; + } + + //----------------------------------------------------------------------- + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * is after midnight at the start of the specified date. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().isAfter(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if this is after the instant of the specified date + */ + public boolean isAfter(OffsetDate other) { + return toEpochSecond() > other.toEpochSecond(); + } + + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * is before midnight at the start of the specified date. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().isBefore(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if this is before the instant of the specified date + */ + public boolean isBefore(OffsetDate other) { + return toEpochSecond() < other.toEpochSecond(); + } + + /** + * Checks if the instant of midnight at the start of this {@code OffsetDate} + * equals midnight at the start of the specified date. + *

    + * This method differs from the comparison in {@link #compareTo} and {@link #equals} + * in that it only compares the instant of the date. This is equivalent to using + * {@code date1.toEpochSecond().equals(date2.toEpochSecond())}. + * + * @param other the other date to compare to, not null + * @return true if the instant equals the instant of the specified date + */ + public boolean isEqual(OffsetDate other) { + return toEpochSecond() == other.toEpochSecond(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this date is equal to another date. + *

    + * The comparison is based on the local-date and the offset. + * To compare for the same instant on the time-line, use {@link #isEqual(OffsetDate)}. + *

    + * Only objects of type {@code OffsetDate} are compared, other types return false. + * To compare the underlying local date of two {@code TemporalAccessor} instances, + * use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OffsetDate) { + OffsetDate other = (OffsetDate) obj; + return date.equals(other.date) && offset.equals(other.offset); + } + return false; + } + + /** + * A hash code for this date. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return date.hashCode() ^ offset.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Outputs this date as a {@code String}, such as {@code 2007-12-03+01:00}. + *

    + * The output will be in the ISO-8601 format {@code yyyy-MM-ddXXXXX}. + * + * @return a string representation of this date, not null + */ + @Override + public String toString() { + return date.toString() + offset.toString(); + } + + /** + * Outputs this date as a {@code String} using the formatter. + *

    + * This date will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted date string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(1);  // identifies this as a OffsetDateTime
    +     *  out.writeObject(date);
    +     *  out.writeObject(offset);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.OFFSET_DATE_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(date); + out.writeObject(offset); + } + + static OffsetDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + LocalDate date = (LocalDate) in.readObject(); + ZoneOffset offset = (ZoneOffset) in.readObject(); + return OffsetDate.of(date, offset); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/OffsetDateTime.java b/jdk/src/share/classes/java/time/temporal/OffsetDateTime.java new file mode 100644 index 00000000000..c7c2295a748 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/OffsetDateTime.java @@ -0,0 +1,1824 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.NANOS; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +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.zone.ZoneRules; +import java.util.Comparator; +import java.util.Objects; + +/** + * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, + * such as {@code 2007-12-03T10:15:30+01:00}. + *

    + * {@code OffsetDateTime} is an immutable representation of a date-time with an offset. + * This class stores all date and time fields, to a precision of nanoseconds, + * as well as the offset from UTC/Greenwich. For example, the value + * "2nd October 2007 at 13:45.30.123456789 +02:00" can be stored in an {@code OffsetDateTime}. + *

    + * {@code OffsetDateTime}, {@link java.time.ZonedDateTime} and {@link java.time.Instant} all store an instant + * on the time-line to nanosecond precision. + * {@code Instant} is the simplest, simply representing the instant. + * {@code OffsetDateTime} adds to the instant the offset from UTC/Greenwich, which allows + * the local date-time to be obtained. + * {@code ZonedDateTime} adds full time-zone rules. + *

    + * It is intended that {@code ZonedDateTime} or {@code Instant} is used to model data + * in simpler applications. This class may be used when modeling date-time concepts in + * more detail, or when communicating to a database or in a network protocol. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class OffsetDateTime + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00'. + * This is the local date-time of midnight at the start of the minimum date + * in the maximum offset (larger offsets are earlier on the time-line). + * This combines {@link LocalDateTime#MIN} and {@link ZoneOffset#MAX}. + * This could be used by an application as a "far past" date-time. + */ + public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX); + /** + * The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'. + * This is the local date-time just before midnight at the end of the maximum date + * in the minimum offset (larger negative offsets are later on the time-line). + * This combines {@link LocalDateTime#MAX} and {@link ZoneOffset#MIN}. + * This could be used by an application as a "far future" date-time. + */ + public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN); + + /** + * Comparator for two {@code OffsetDateTime} instances based solely on the instant. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying instant. + * + * @see #isAfter + * @see #isBefore + * @see #isEqual + */ + public static final Comparator INSTANT_COMPARATOR = new Comparator() { + @Override + public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) { + int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); + if (cmp == 0) { + cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay()); + } + return cmp; + } + }; + + /** + * Serialization version. + */ + private static final long serialVersionUID = 2287754244819255394L; + + /** + * The local date-time. + */ + private final LocalDateTime dateTime; + /** + * The offset from UTC/Greenwich. + */ + private final ZoneOffset offset; + + //----------------------------------------------------------------------- + /** + * Obtains the current date-time from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date-time. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current date-time using the system clock, not null + */ + public static OffsetDateTime now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current date-time from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current date-time. + * Specifying the time-zone avoids dependence on the default time-zone. + * The offset will be calculated from the specified time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current date-time using the system clock, not null + */ + public static OffsetDateTime now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current date-time from the specified clock. + *

    + * This will query the specified clock to obtain the current date-time. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date-time, not null + */ + public static OffsetDateTime now(Clock clock) { + Objects.requireNonNull(clock, "clock"); + final Instant now = clock.instant(); // called once + return ofInstant(now, clock.getZone().getRules().getOffset(now)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a date, time and offset. + *

    + * This creates an offset date-time with the specified local date, time and offset. + * + * @param date the local date, not null + * @param time the local time, not null + * @param offset the zone offset, not null + * @return the offset date-time, not null + */ + public static OffsetDateTime of(LocalDate date, LocalTime time, ZoneOffset offset) { + LocalDateTime dt = LocalDateTime.of(date, time); + return new OffsetDateTime(dt, offset); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a date-time and offset. + *

    + * This creates an offset date-time with the specified local date-time and offset. + * + * @param dateTime the local date-time, not null + * @param offset the zone offset, not null + * @return the offset date-time, not null + */ + public static OffsetDateTime of(LocalDateTime dateTime, ZoneOffset offset) { + return new OffsetDateTime(dateTime, offset); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a {@code ZonedDateTime}. + *

    + * This creates an offset date-time with the same local date-time and offset as + * the zoned date-time. The result will have the same instant as the input. + * + * @param zonedDateTime the zoned date-time to convert from, not null + * @return the offset date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public static OffsetDateTime of(ZonedDateTime zonedDateTime) { + Objects.requireNonNull(zonedDateTime, "zonedDateTime"); + return new OffsetDateTime(zonedDateTime.getDateTime(), zonedDateTime.getOffset()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID. + *

    + * This creates an offset date-time with the same instant as that specified. + * Finding the offset from UTC/Greenwich is simple as there is only one valid + * offset for each instant. + * + * @param instant the instant to create the date-time from, not null + * @param zone the time-zone, which may be an offset, not null + * @return the offset date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); + return new OffsetDateTime(ldt, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code OffsetDateTime}. + *

    + * The conversion extracts and combines {@code LocalDateTime} and {@code ZoneOffset}. + * If that fails it will try to extract and combine {@code Instant} and {@code ZoneOffset}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code OffsetDateTime::from}. + * + * @param temporal the temporal object to convert, not null + * @return the offset date-time, not null + * @throws DateTimeException if unable to convert to an {@code OffsetDateTime} + */ + public static OffsetDateTime from(TemporalAccessor temporal) { + if (temporal instanceof OffsetDateTime) { + return (OffsetDateTime) temporal; + } + ZoneOffset offset = ZoneOffset.from(temporal); + try { + try { + LocalDateTime ldt = LocalDateTime.from(temporal); + return OffsetDateTime.of(ldt, offset); + } catch (DateTimeException ignore) { + Instant instant = Instant.from(temporal); + return OffsetDateTime.ofInstant(instant, offset); + } + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a text string + * such as {@code 2007-12-03T10:15:30+01:00}. + *

    + * The string must represent a valid date-time and is parsed using + * {@link java.time.format.DateTimeFormatters#isoOffsetDateTime()}. + * + * @param text the text to parse such as "2007-12-03T10:15:30+01:00", not null + * @return the parsed offset date-time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDateTime parse(CharSequence text) { + return parse(text, DateTimeFormatters.isoOffsetDateTime()); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a date-time. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed offset date-time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDateTime parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, OffsetDateTime::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param dateTime the local date-time, not null + * @param offset the zone offset, not null + */ + private OffsetDateTime(LocalDateTime dateTime, ZoneOffset offset) { + this.dateTime = Objects.requireNonNull(dateTime, "dateTime"); + this.offset = Objects.requireNonNull(offset, "offset"); + } + + /** + * Returns a new date-time based on this one, returning {@code this} where possible. + * + * @param dateTime the date-time to create with, not null + * @param offset the zone offset to create with, not null + */ + private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) { + if (this.dateTime == dateTime && this.offset.equals(offset)) { + return this; + } + return new OffsetDateTime(dateTime, offset); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this date-time can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

      + *
    • {@code NANO_OF_SECOND} + *
    • {@code NANO_OF_DAY} + *
    • {@code MICRO_OF_SECOND} + *
    • {@code MICRO_OF_DAY} + *
    • {@code MILLI_OF_SECOND} + *
    • {@code MILLI_OF_DAY} + *
    • {@code SECOND_OF_MINUTE} + *
    • {@code SECOND_OF_DAY} + *
    • {@code MINUTE_OF_HOUR} + *
    • {@code MINUTE_OF_DAY} + *
    • {@code HOUR_OF_AMPM} + *
    • {@code CLOCK_HOUR_OF_AMPM} + *
    • {@code HOUR_OF_DAY} + *
    • {@code CLOCK_HOUR_OF_DAY} + *
    • {@code AMPM_OF_DAY} + *
    • {@code DAY_OF_WEEK} + *
    • {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} + *
    • {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} + *
    • {@code DAY_OF_MONTH} + *
    • {@code DAY_OF_YEAR} + *
    • {@code EPOCH_DAY} + *
    • {@code ALIGNED_WEEK_OF_MONTH} + *
    • {@code ALIGNED_WEEK_OF_YEAR} + *
    • {@code MONTH_OF_YEAR} + *
    • {@code EPOCH_MONTH} + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    • {@code INSTANT_SECONDS} + *
    • {@code OFFSET_SECONDS} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this date-time, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + return field instanceof ChronoField || (field != null && field.doIsSupported(this)); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This date-time is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { + return field.range(); + } + return dateTime.range(field); + } + return field.doRange(this); + } + + /** + * Gets the value of the specified field from this date-time as an {@code int}. + *

    + * This queries this date-time for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY}, + * {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too + * large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field); + case OFFSET_SECONDS: return getOffset().getTotalSeconds(); + } + return dateTime.get(field); + } + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this date-time as a {@code long}. + *

    + * This queries this date-time for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case INSTANT_SECONDS: return toEpochSecond(); + case OFFSET_SECONDS: return getOffset().getTotalSeconds(); + } + return dateTime.getLong(field); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the zone offset, such as '+01:00'. + *

    + * This is the offset of the local date-time from UTC/Greenwich. + * + * @return the zone offset, not null + */ + public ZoneOffset getOffset() { + return offset; + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring + * that the result has the same local date-time. + *

    + * This method returns an object with the same {@code LocalDateTime} and the specified {@code ZoneOffset}. + * No calculation is needed or performed. + * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03T10:30+03:00}. + *

    + * To take into account the difference between the offsets, and adjust the time fields, + * use {@link #withOffsetSameInstant}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null + */ + public OffsetDateTime withOffsetSameLocal(ZoneOffset offset) { + return with(dateTime, offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring + * that the result is at the same instant. + *

    + * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalDateTime} + * adjusted by the difference between the two offsets. + * This will result in the old and new objects representing the same instant. + * This is useful for finding the local time in a different offset. + * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03T11:30+03:00}. + *

    + * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime withOffsetSameInstant(ZoneOffset offset) { + if (offset.equals(this.offset)) { + return this; + } + int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds(); + LocalDateTime adjusted = dateTime.plusSeconds(difference); + return new OffsetDateTime(adjusted, offset); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDateTime} part of this offset date-time. + *

    + * This returns a {@code LocalDateTime} with the same year, month, day and time + * as this date-time. + * + * @return the local date-time part of this date-time, not null + */ + public LocalDateTime getDateTime() { + return dateTime; + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDate} part of this date-time. + *

    + * This returns a {@code LocalDate} with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public LocalDate getDate() { + return dateTime.getDate(); + } + + /** + * Gets the year field. + *

    + * This method returns the primitive {@code int} value for the year. + *

    + * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return dateTime.getYear(); + } + + /** + * Gets the month-of-year field from 1 to 12. + *

    + * This method returns the month as an {@code int} from 1 to 12. + * Application code is frequently clearer if the enum {@link Month} + * is used by calling {@link #getMonth()}. + * + * @return the month-of-year, from 1 to 12 + * @see #getMonth() + */ + public int getMonthValue() { + return dateTime.getMonthValue(); + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + *

    + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + * @see #getMonthValue() + */ + public Month getMonth() { + return dateTime.getMonth(); + } + + /** + * Gets the day-of-month field. + *

    + * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return dateTime.getDayOfMonth(); + } + + /** + * Gets the day-of-year field. + *

    + * This method returns the primitive {@code int} value for the day-of-year. + * + * @return the day-of-year, from 1 to 365, or 366 in a leap year + */ + public int getDayOfYear() { + return dateTime.getDayOfYear(); + } + + /** + * Gets the day-of-week field, which is an enum {@code DayOfWeek}. + *

    + * This method returns the enum {@link java.time.DayOfWeek} for the day-of-week. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link java.time.DayOfWeek#getValue() int value}. + *

    + * Additional information can be obtained from the {@code DayOfWeek}. + * This includes textual names of the values. + * + * @return the day-of-week, not null + */ + public DayOfWeek getDayOfWeek() { + return dateTime.getDayOfWeek(); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalTime} part of this date-time. + *

    + * This returns a {@code LocalTime} with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public LocalTime getTime() { + return dateTime.getTime(); + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return dateTime.getHour(); + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return dateTime.getMinute(); + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return dateTime.getSecond(); + } + + /** + * Gets the nano-of-second field. + * + * @return the nano-of-second, from 0 to 999,999,999 + */ + public int getNano() { + return dateTime.getNano(); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this date-time. + *

    + * This returns a new {@code OffsetDateTime}, based on this one, with the date-time adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

    + * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the date to the last day of the month. + * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}. + * These include finding the "last day of the month" and "next Wednesday". + * Key date-time classes also implement the {@code TemporalAdjuster} interface, + * such as {@link Month} and {@link java.time.temporal.MonthDay MonthDay}. + * The adjuster is responsible for handling special cases, such as the varying + * lengths of month and leap years. + *

    + * For example this code returns a date on the last day of July: + *

    +     *  import static java.time.Month.*;
    +     *  import static java.time.temporal.Adjusters.*;
    +     *
    +     *  result = offsetDateTime.with(JULY).with(lastDayOfMonth());
    +     * 
    + *

    + * The classes {@link LocalDate}, {@link LocalTime} and {@link ZoneOffset} implement + * {@code TemporalAdjuster}, thus this method can be used to change the date, time or offset: + *

    +     *  result = offsetDateTime.with(date);
    +     *  result = offsetDateTime.with(time);
    +     *  result = offsetDateTime.with(offset);
    +     * 
    + *

    + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return an {@code OffsetDateTime} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime with(TemporalAdjuster adjuster) { + // optimizations + if (adjuster instanceof LocalDate || adjuster instanceof LocalTime || adjuster instanceof LocalDateTime) { + return with(dateTime.with(adjuster), offset); + } else if (adjuster instanceof Instant) { + return ofInstant((Instant) adjuster, offset); + } else if (adjuster instanceof ZoneOffset) { + return with(dateTime, (ZoneOffset) adjuster); + } else if (adjuster instanceof OffsetDateTime) { + return (OffsetDateTime) adjuster; + } + return (OffsetDateTime) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this date-time with the specified field set to a new value. + *

    + * This returns a new {@code OffsetDateTime}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year, month or day-of-month. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

    + * In some cases, changing the specified field can cause the resulting date-time to become invalid, + * such as changing the month from 31st January to February would make the day-of-month invalid. + * In cases like this, the field is responsible for resolving the date. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + *

    + * If the field is a {@link ChronoField} then the adjustment is implemented here. + *

    + * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant. + * The offset and nano-of-second are unchanged. + * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown. + *

    + * The {@code OFFSET_SECONDS} field will return a date-time with the specified offset. + * The local date-time is unaltered. If the new offset value is outside the valid range + * then a {@code DateTimeException} will be thrown. + *

    + * The other {@link #isSupported(TemporalField) supported fields} will behave as per + * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}. + * In this case, the offset is not part of the calculation and will be unchanged. + *

    + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + switch (f) { + case INSTANT_SECONDS: return ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset); + case OFFSET_SECONDS: { + return with(dateTime, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); + } + } + return with(dateTime.with(field, newValue), offset); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR + * @return an {@code OffsetDateTime} based on this date-time with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public OffsetDateTime withYear(int year) { + return with(dateTime.withYear(year), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the month-of-year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the result, from 1 (January) to 12 (December) + * @return an {@code OffsetDateTime} based on this date-time with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public OffsetDateTime withMonth(int month) { + return with(dateTime.withMonth(month), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the day-of-month altered. + * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31 + * @return an {@code OffsetDateTime} based on this date-time with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public OffsetDateTime withDayOfMonth(int dayOfMonth) { + return with(dateTime.withDayOfMonth(dayOfMonth), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the day-of-year altered. + * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366 + * @return an {@code OffsetDateTime} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-year value is invalid + * @throws DateTimeException if the day-of-year is invalid for the year + */ + public OffsetDateTime withDayOfYear(int dayOfYear) { + return with(dateTime.withDayOfYear(dayOfYear), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the hour-of-day value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hour the hour-of-day to set in the result, from 0 to 23 + * @return an {@code OffsetDateTime} based on this date-time with the requested hour, not null + * @throws DateTimeException if the hour value is invalid + */ + public OffsetDateTime withHour(int hour) { + return with(dateTime.withHour(hour), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the minute-of-hour value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minute the minute-of-hour to set in the result, from 0 to 59 + * @return an {@code OffsetDateTime} based on this date-time with the requested minute, not null + * @throws DateTimeException if the minute value is invalid + */ + public OffsetDateTime withMinute(int minute) { + return with(dateTime.withMinute(minute), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the second-of-minute value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param second the second-of-minute to set in the result, from 0 to 59 + * @return an {@code OffsetDateTime} based on this date-time with the requested second, not null + * @throws DateTimeException if the second value is invalid + */ + public OffsetDateTime withSecond(int second) { + return with(dateTime.withSecond(second), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the nano-of-second value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 + * @return an {@code OffsetDateTime} based on this date-time with the requested nanosecond, not null + * @throws DateTimeException if the nanos value is invalid + */ + public OffsetDateTime withNano(int nanoOfSecond) { + return with(dateTime.withNano(nanoOfSecond), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the time truncated. + *

    + * Truncation returns a copy of the original date-time with fields + * smaller than the specified unit set to zero. + * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit + * will set the second-of-minute and nano-of-second field to zero. + *

    + * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time + * units with an exact duration can be used, other units throw an exception. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param unit the unit to truncate to, not null + * @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null + * @throws DateTimeException if unable to truncate + */ + public OffsetDateTime truncatedTo(TemporalUnit unit) { + return with(dateTime.truncatedTo(unit), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date-time with the specified period added. + *

    + * This method returns a new date-time based on this time with the specified period added. + * The adder is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #plus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adder the adder to use, not null + * @return an {@code OffsetDateTime} based on this date-time with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime plus(TemporalAdder adder) { + return (OffsetDateTime) adder.addTo(this); + } + + /** + * Returns a copy of this date-time with the specified period added. + *

    + * This method returns a new date-time based on this date-time with the specified period added. + * This can be used to add any period that is defined by a unit, for example to add years, months or days. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the period to add, not null + * @return an {@code OffsetDateTime} based on this date-time with the specified period added, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + @Override + public OffsetDateTime plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(dateTime.plus(amountToAdd, unit), offset); + } + return unit.doPlus(this, amountToAdd); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in years added. + *

    + * This method adds the specified amount to the years field in three steps: + *

      + *
    1. Add the input years to the year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2008-02-29 (leap year) plus one year would result in the + * invalid date 2009-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2009-02-28, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param years the years to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the years added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusYears(long years) { + return with(dateTime.plusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in months added. + *

    + * This method adds the specified amount to the months field in three steps: + *

      + *
    1. Add the input months to the month-of-year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2007-03-31 plus one month would result in the invalid date + * 2007-04-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-04-30, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param months the months to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the months added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusMonths(long months) { + return with(dateTime.plusMonths(months), offset); + } + + /** + * Returns a copy of this OffsetDateTime with the specified period in weeks added. + *

    + * This method adds the specified amount in weeks to the days field incrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 plus one week would result in the 2009-01-07. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the weeks added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusWeeks(long weeks) { + return with(dateTime.plusWeeks(weeks), offset); + } + + /** + * Returns a copy of this OffsetDateTime with the specified period in days added. + *

    + * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 plus one day would result in the 2009-01-01. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusDays(long days) { + return with(dateTime.plusDays(days), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in hours added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the hours added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusHours(long hours) { + return with(dateTime.plusHours(hours), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the minutes added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusMinutes(long minutes) { + return with(dateTime.plusMinutes(minutes), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the seconds added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusSeconds(long seconds) { + return with(dateTime.plusSeconds(seconds), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds added, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + public OffsetDateTime plusNanos(long nanos) { + return with(dateTime.plusNanos(nanos), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date-time with the specified period subtracted. + *

    + * This method returns a new date-time based on this time with the specified period subtracted. + * The subtractor is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #minus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param subtractor the subtractor to use, not null + * @return an {@code OffsetDateTime} based on this date-time with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime minus(TemporalSubtractor subtractor) { + return (OffsetDateTime) subtractor.subtractFrom(this); + } + + /** + * Returns a copy of this date-time with the specified period subtracted. + *

    + * This method returns a new date-time based on this date-time with the specified period subtracted. + * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the period to subtract, not null + * @return an {@code OffsetDateTime} based on this date-time with the specified period subtracted, not null + */ + @Override + public OffsetDateTime minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in years subtracted. + *

    + * This method subtracts the specified amount from the years field in three steps: + *

      + *
    1. Subtract the input years to the year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2008-02-29 (leap year) minus one year would result in the + * invalid date 2009-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2009-02-28, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param years the years to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusYears(long years) { + return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in months subtracted. + *

    + * This method subtracts the specified amount from the months field in three steps: + *

      + *
    1. Subtract the input months to the month-of-year field
    2. + *
    3. Check if the resulting date would be invalid
    4. + *
    5. Adjust the day-of-month to the last valid day if necessary
    6. + *
    + *

    + * For example, 2007-03-31 minus one month would result in the invalid date + * 2007-04-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-04-30, is selected instead. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param months the months to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusMonths(long months) { + return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in weeks subtracted. + *

    + * This method subtracts the specified amount in weeks from the days field decrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 minus one week would result in the 2009-01-07. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the weeks subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusWeeks(long weeks) { + return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in days subtracted. + *

    + * This method subtracts the specified amount from the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *

    + * For example, 2008-12-31 minus one day would result in the 2009-01-01. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param days the days to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusDays(long days) { + return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in hours subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the hours subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusHours(long hours) { + return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the minutes subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusMinutes(long minutes) { + return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the seconds subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusSeconds(long seconds) { + return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusNanos(long nanos) { + return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos)); + } + + //----------------------------------------------------------------------- + /** + * Queries this date-time using the specified query. + *

    + * This queries this date-time using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) getDate().getChrono(); + } else if (query == Queries.precision()) { + return (R) NANOS; + } else if (query == Queries.offset() || query == Queries.zone()) { + return (R) getOffset(); + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have the same offset, date + * and time as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the offset, date and time changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * three times, passing {@link ChronoField#OFFSET_SECONDS}, + * {@link ChronoField#EPOCH_DAY} and {@link ChronoField#NANO_OF_DAY} as the fields. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisOffsetDateTime.adjustInto(temporal);
    +     *   temporal = temporal.with(thisOffsetDateTime);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + return temporal + .with(OFFSET_SECONDS, getOffset().getTotalSeconds()) + .with(EPOCH_DAY, getDate().toEpochDay()) + .with(NANO_OF_DAY, getTime().toNanoOfDay()); + } + + /** + * Calculates the period between this date-time and another date-time in + * terms of the specified unit. + *

    + * This calculates the period between two date-times in terms of a single unit. + * The start and end points are {@code this} and the specified date-time. + * The result will be negative if the end is before the start. + * For example, the period in days between two date-times can be calculated + * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + *

    + * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}. + * If the offset differs between the two date-times, the specified + * end date-time is normalized to have the same offset as this date-time. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two date-times. + * For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z + * will only be one month as it is one minute short of two months. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, MONTHS);   // this method
    +     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, + * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS}, + * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES}, + * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this date-time and the end date-time + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + if (endDateTime instanceof OffsetDateTime == false) { + Objects.requireNonNull(endDateTime, "endDateTime"); + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + if (unit instanceof ChronoUnit) { + OffsetDateTime end = (OffsetDateTime) endDateTime; + end = end.withOffsetSameInstant(offset); + return dateTime.periodUntil(end.dateTime, unit); + } + return unit.between(this, endDateTime).getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns a zoned date-time formed from the instant represented by this + * date-time and the specified zone ID. + *

    + * This conversion will ignore the visible local date-time and use the underlying instant instead. + * This avoids any problems with local time-line gaps or overlaps. + * The result might have different values for fields such as hour, minute an even day. + *

    + * To attempt to retain the values of the fields, use {@link #atZoneSimilarLocal(ZoneId)}. + * To use the offset as the zone ID, use {@link #toZonedDateTime()}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param zone the time-zone to use, not null + * @return the zoned date-time formed from this date-time, not null + */ + public ZonedDateTime atZoneSameInstant(ZoneId zone) { + return ZonedDateTime.ofInstant(dateTime, offset, zone); + } + + /** + * Returns a zoned date-time formed from this date-time and the specified zone ID. + *

    + * Time-zone rules, such as daylight savings, mean that not every time on the + * local time-line exists. If the local date-time is in a gap or overlap according to + * the rules then a resolver is used to determine the resultant local time and offset. + * This method uses {@link ZonedDateTime#ofLocal(LocalDateTime, ZoneId, ZoneOffset)} + * to retain the offset from this instance if possible. + *

    + * Finer control over gaps and overlaps is available in two ways. + * If you simply want to use the later offset at overlaps then call + * {@link ZonedDateTime#withLaterOffsetAtOverlap()} immediately after this method. + *

    + * To create a zoned date-time at the same instant irrespective of the local time-line, + * use {@link #atZoneSameInstant(ZoneId)}. + * To use the offset as the zone ID, use {@link #toZonedDateTime()}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param zone the time-zone to use, not null + * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null + */ + public ZonedDateTime atZoneSimilarLocal(ZoneId zone) { + return ZonedDateTime.ofLocal(dateTime, zone, offset); + } + + //----------------------------------------------------------------------- + /** + * Converts this date-time to an {@code OffsetDate}. + *

    + * This returns an offset date with the same local date and offset. + * + * @return an OffsetDate representing the date and offset, not null + */ + public OffsetDate toOffsetDate() { + return OffsetDate.of(dateTime.getDate(), offset); + } + + /** + * Converts this date-time to an {@code OffsetTime}. + *

    + * This returns an offset time with the same local time and offset. + * + * @return an OffsetTime representing the time and offset, not null + */ + public OffsetTime toOffsetTime() { + return OffsetTime.of(dateTime.getTime(), offset); + } + + /** + * Converts this date-time to a {@code ZonedDateTime} using the offset as the zone ID. + *

    + * This creates the simplest possible {@code ZonedDateTime} using the offset + * as the zone ID. + *

    + * To control the time-zone used, see {@link #atZoneSameInstant(ZoneId)} and + * {@link #atZoneSimilarLocal(ZoneId)}. + * + * @return a zoned date-time representing the same local date-time and offset, not null + */ + public ZonedDateTime toZonedDateTime() { + return ZonedDateTime.of(dateTime, offset); + } + + /** + * Converts this date-time to an {@code Instant}. + * + * @return an {@code Instant} representing the same instant, not null + */ + public Instant toInstant() { + return dateTime.toInstant(offset); + } + + /** + * Converts this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z. + *

    + * This allows this date-time to be converted to a value of the + * {@link ChronoField#INSTANT_SECONDS epoch-seconds} field. This is primarily + * intended for low-level conversions rather than general application usage. + * + * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z + */ + public long toEpochSecond() { + return dateTime.toEpochSecond(offset); + } + + //----------------------------------------------------------------------- + /** + * Compares this {@code OffsetDateTime} to another date-time. + *

    + * The comparison is based on the instant then on the local date-time. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * For example, the following is the comparator order: + *

      + *
    1. {@code 2008-12-03T10:30+01:00}
    2. + *
    3. {@code 2008-12-03T11:00+01:00}
    4. + *
    5. {@code 2008-12-03T12:00+02:00}
    6. + *
    7. {@code 2008-12-03T11:30+01:00}
    8. + *
    9. {@code 2008-12-03T12:00+01:00}
    10. + *
    11. {@code 2008-12-03T12:30+01:00}
    12. + *
    + * Values #2 and #3 represent the same instant on the time-line. + * When two values represent the same instant, the local date-time is compared + * to distinguish them. This step is needed to make the ordering + * consistent with {@code equals()}. + * + * @param other the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(OffsetDateTime other) { + if (getOffset().equals(other.getOffset())) { + return getDateTime().compareTo(other.getDateTime()); + } + int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); + if (cmp == 0) { + cmp = getTime().getNano() - other.getTime().getNano(); + if (cmp == 0) { + cmp = getDateTime().compareTo(other.getDateTime()); + } + } + return cmp; + } + + //----------------------------------------------------------------------- + /** + * Checks if the instant of this date-time is after that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} and {@link #equals} in that it + * only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. + * + * @param other the other date-time to compare to, not null + * @return true if this is after the instant of the specified date-time + */ + public boolean isAfter(OffsetDateTime other) { + long thisEpochSec = toEpochSecond(); + long otherEpochSec = other.toEpochSecond(); + return thisEpochSec > otherEpochSec || + (thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano()); + } + + /** + * Checks if the instant of this date-time is before that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. + * + * @param other the other date-time to compare to, not null + * @return true if this is before the instant of the specified date-time + */ + public boolean isBefore(OffsetDateTime other) { + long thisEpochSec = toEpochSecond(); + long otherEpochSec = other.toEpochSecond(); + return thisEpochSec < otherEpochSec || + (thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano()); + } + + /** + * Checks if the instant of this date-time is equal to that of the specified date-time. + *

    + * This method differs from the comparison in {@link #compareTo} and {@link #equals} + * in that it only compares the instant of the date-time. This is equivalent to using + * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. + * + * @param other the other date-time to compare to, not null + * @return true if the instant equals the instant of the specified date-time + */ + public boolean isEqual(OffsetDateTime other) { + return toEpochSecond() == other.toEpochSecond() && + getTime().getNano() == other.getTime().getNano(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this date-time is equal to another date-time. + *

    + * The comparison is based on the local date-time and the offset. + * To compare for the same instant on the time-line, use {@link #isEqual}. + * Only objects of type {@code OffsetDateTime} are compared, other types return false. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date-time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OffsetDateTime) { + OffsetDateTime other = (OffsetDateTime) obj; + return dateTime.equals(other.dateTime) && offset.equals(other.offset); + } + return false; + } + + /** + * A hash code for this date-time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return dateTime.hashCode() ^ offset.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30+01:00}. + *

    + * The output will be one of the following ISO-8601 formats: + *

      + *
    • {@code yyyy-MM-dd'T'HH:mmXXXXX}
    • + *
    • {@code yyyy-MM-dd'T'HH:mm:ssXXXXX}
    • + *
    • {@code yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX}
    • + *
    • {@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}
    • + *
    • {@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}
    • + *

    + * The format used will be the shortest that outputs the full value of + * the time where the omitted parts are implied to be zero. + * + * @return a string representation of this date-time, not null + */ + @Override + public String toString() { + return dateTime.toString() + offset.toString(); + } + + /** + * Outputs this date-time as a {@code String} using the formatter. + *

    + * This date-time will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted date-time string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(3);  // identifies this as a OffsetDateTime
    +     *  out.writeObject(dateTime);
    +     *  out.writeObject(offset);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.OFFSET_DATE_TIME_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(dateTime); + out.writeObject(offset); + } + + static OffsetDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + LocalDateTime dateTime = (LocalDateTime) in.readObject(); + ZoneOffset offset = (ZoneOffset) in.readObject(); + return OffsetDateTime.of(dateTime, offset); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/OffsetTime.java b/jdk/src/share/classes/java/time/temporal/OffsetTime.java new file mode 100644 index 00000000000..390b1b199d3 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/OffsetTime.java @@ -0,0 +1,1311 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_HOUR; +import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_MINUTE; +import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_SECOND; +import static java.time.temporal.ChronoLocalDateTimeImpl.SECONDS_PER_DAY; +import static java.time.temporal.ChronoUnit.NANOS; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +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.zone.ZoneRules; +import java.util.Objects; + +/** + * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system, + * such as {@code 10:15:30+01:00}. + *

    + * {@code OffsetTime} is an immutable date-time object that represents a time, often + * viewed as hour-minute-second-offset. + * This class stores all time fields, to a precision of nanoseconds, + * as well as a zone offset. + * For example, the value "13:45.30.123456789+02:00" can be stored + * in an {@code OffsetTime}. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class OffsetTime + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The minimum supported {@code OffsetTime}, '00:00:00+18:00'. + * This is the time of midnight at the start of the day in the maximum offset + * (larger offsets are earlier on the time-line). + * This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}. + * This could be used by an application as a "far past" date. + */ + public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX); + /** + * The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'. + * This is the time just before midnight at the end of the day in the minimum offset + * (larger negative offsets are later on the time-line). + * This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}. + * This could be used by an application as a "far future" date. + */ + public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN); + + /** + * Serialization version. + */ + private static final long serialVersionUID = 7264499704384272492L; + + /** + * The local date-time. + */ + private final LocalTime time; + /** + * The offset from UTC/Greenwich. + */ + private final ZoneOffset offset; + + //----------------------------------------------------------------------- + /** + * Obtains the current time from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current time. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current time using the system clock, not null + */ + public static OffsetTime now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current time from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current time. + * Specifying the time-zone avoids dependence on the default time-zone. + * The offset will be calculated from the specified time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current time using the system clock, not null + */ + public static OffsetTime now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current time from the specified clock. + *

    + * This will query the specified clock to obtain the current time. + * The offset will be calculated from the time-zone in the clock. + *

    + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current time, not null + */ + public static OffsetTime now(Clock clock) { + Objects.requireNonNull(clock, "clock"); + final Instant now = clock.instant(); // called once + return ofInstant(now, clock.getZone().getRules().getOffset(now)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetTime} from a local time and an offset. + * + * @param time the local time, not null + * @param offset the zone offset, not null + * @return the offset time, not null + */ + public static OffsetTime of(LocalTime time, ZoneOffset offset) { + return new OffsetTime(time, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID. + *

    + * This creates an offset time with the same instant as that specified. + * Finding the offset from UTC/Greenwich is simple as there is only one valid + * offset for each instant. + *

    + * The date component of the instant is dropped during the conversion. + * This means that the conversion can never fail due to the instant being + * out of the valid range of dates. + * + * @param instant the instant to create the time from, not null + * @param zone the time-zone, which may be an offset, not null + * @return the offset time, not null + */ + public static OffsetTime ofInstant(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + long secsOfDay = instant.getEpochSecond() % SECONDS_PER_DAY; + secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY; + if (secsOfDay < 0) { + secsOfDay += SECONDS_PER_DAY; + } + LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, instant.getNano()); + return new OffsetTime(time, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetTime} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code OffsetTime}. + *

    + * The conversion extracts and combines {@code LocalTime} and {@code ZoneOffset}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code OffsetTime::from}. + * + * @param temporal the temporal object to convert, not null + * @return the offset time, not null + * @throws DateTimeException if unable to convert to an {@code OffsetTime} + */ + public static OffsetTime from(TemporalAccessor temporal) { + if (temporal instanceof OffsetTime) { + return (OffsetTime) temporal; + } + try { + LocalTime time = LocalTime.from(temporal); + ZoneOffset offset = ZoneOffset.from(temporal); + return new OffsetTime(time, offset); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}. + *

    + * The string must represent a valid time and is parsed using + * {@link java.time.format.DateTimeFormatters#isoOffsetTime()}. + * + * @param text the text to parse such as "10:15:30+01:00", not null + * @return the parsed local time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetTime parse(CharSequence text) { + return parse(text, DateTimeFormatters.isoOffsetTime()); + } + + /** + * Obtains an instance of {@code OffsetTime} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a time. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed offset time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, OffsetTime::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param time the local time, not null + * @param offset the zone offset, not null + */ + private OffsetTime(LocalTime time, ZoneOffset offset) { + this.time = Objects.requireNonNull(time, "time"); + this.offset = Objects.requireNonNull(offset, "offset"); + } + + /** + * Returns a new time based on this one, returning {@code this} where possible. + * + * @param time the time to create with, not null + * @param offset the zone offset to create with, not null + */ + private OffsetTime with(LocalTime time, ZoneOffset offset) { + if (this.time == time && this.offset.equals(offset)) { + return this; + } + return new OffsetTime(time, offset); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this time can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

      + *
    • {@code NANO_OF_SECOND} + *
    • {@code NANO_OF_DAY} + *
    • {@code MICRO_OF_SECOND} + *
    • {@code MICRO_OF_DAY} + *
    • {@code MILLI_OF_SECOND} + *
    • {@code MILLI_OF_DAY} + *
    • {@code SECOND_OF_MINUTE} + *
    • {@code SECOND_OF_DAY} + *
    • {@code MINUTE_OF_HOUR} + *
    • {@code MINUTE_OF_DAY} + *
    • {@code HOUR_OF_AMPM} + *
    • {@code CLOCK_HOUR_OF_AMPM} + *
    • {@code HOUR_OF_DAY} + *
    • {@code CLOCK_HOUR_OF_DAY} + *
    • {@code AMPM_OF_DAY} + *
    • {@code OFFSET_SECONDS} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this time, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return ((ChronoField) field).isTimeField() || field == OFFSET_SECONDS; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This time is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return field.range(); + } + return time.range(field); + } + return field.doRange(this); + } + + /** + * Gets the value of the specified field from this time as an {@code int}. + *

    + * This queries this time for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY} + * which are too large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this time as a {@code long}. + *

    + * This queries this time for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this time. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + return getOffset().getTotalSeconds(); + } + return time.getLong(field); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the zone offset, such as '+01:00'. + *

    + * This is the offset of the local time from UTC/Greenwich. + * + * @return the zone offset, not null + */ + public ZoneOffset getOffset() { + return offset; + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified offset ensuring + * that the result has the same local time. + *

    + * This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}. + * No calculation is needed or performed. + * For example, if this time represents {@code 10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 10:30+03:00}. + *

    + * To take into account the difference between the offsets, and adjust the time fields, + * use {@link #withOffsetSameInstant}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetTime} based on this time with the requested offset, not null + */ + public OffsetTime withOffsetSameLocal(ZoneOffset offset) { + return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified offset ensuring + * that the result is at the same instant on an implied day. + *

    + * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime} + * adjusted by the difference between the two offsets. + * This will result in the old and new objects representing the same instant an an implied day. + * This is useful for finding the local time in a different offset. + * For example, if this time represents {@code 10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 11:30+03:00}. + *

    + * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetTime} based on this time with the requested offset, not null + */ + public OffsetTime withOffsetSameInstant(ZoneOffset offset) { + if (offset.equals(this.offset)) { + return this; + } + int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds(); + LocalTime adjusted = time.plusSeconds(difference); + return new OffsetTime(adjusted, offset); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalTime} part of this date-time. + *

    + * This returns a {@code LocalTime} with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public LocalTime getTime() { + return time; + } + + //----------------------------------------------------------------------- + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return time.getHour(); + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return time.getMinute(); + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return time.getSecond(); + } + + /** + * Gets the nano-of-second field. + * + * @return the nano-of-second, from 0 to 999,999,999 + */ + public int getNano() { + return time.getNano(); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this time. + *

    + * This returns a new {@code OffsetTime}, based on this one, with the time adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

    + * A simple adjuster might simply set the one of the fields, such as the hour field. + * A more complex adjuster might set the time to the last hour of the day. + *

    + * The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster}, + * thus this method can be used to change the time or offset: + *

    +     *  result = offsetTime.with(time);
    +     *  result = offsetTime.with(offset);
    +     * 
    + *

    + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetTime with(TemporalAdjuster adjuster) { + // optimizations + if (adjuster instanceof LocalTime) { + return with((LocalTime) adjuster, offset); + } else if (adjuster instanceof ZoneOffset) { + return with(time, (ZoneOffset) adjuster); + } else if (adjuster instanceof OffsetTime) { + return (OffsetTime) adjuster; + } + return (OffsetTime) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this time with the specified field set to a new value. + *

    + * This returns a new {@code OffsetTime}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the hour, minute or second. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the adjustment is implemented here. + *

    + * The {@code OFFSET_SECONDS} field will return a time with the specified offset. + * The local time is unaltered. If the new offset value is outside the valid range + * then a {@code DateTimeException} will be thrown. + *

    + * The other {@link #isSupported(TemporalField) supported fields} will behave as per + * the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}. + * In this case, the offset is not part of the calculation and will be unchanged. + *

    + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an {@code OffsetTime} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetTime with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + if (field == OFFSET_SECONDS) { + ChronoField f = (ChronoField) field; + return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); + } + return with(time.with(field, newValue), offset); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetTime} with the hour-of-day value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hour the hour-of-day to set in the result, from 0 to 23 + * @return an {@code OffsetTime} based on this time with the requested hour, not null + * @throws DateTimeException if the hour value is invalid + */ + public OffsetTime withHour(int hour) { + return with(time.withHour(hour), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the minute-of-hour value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minute the minute-of-hour to set in the result, from 0 to 59 + * @return an {@code OffsetTime} based on this time with the requested minute, not null + * @throws DateTimeException if the minute value is invalid + */ + public OffsetTime withMinute(int minute) { + return with(time.withMinute(minute), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the second-of-minute value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param second the second-of-minute to set in the result, from 0 to 59 + * @return an {@code OffsetTime} based on this time with the requested second, not null + * @throws DateTimeException if the second value is invalid + */ + public OffsetTime withSecond(int second) { + return with(time.withSecond(second), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the nano-of-second value altered. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 + * @return an {@code OffsetTime} based on this time with the requested nanosecond, not null + * @throws DateTimeException if the nanos value is invalid + */ + public OffsetTime withNano(int nanoOfSecond) { + return with(time.withNano(nanoOfSecond), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetTime} with the time truncated. + *

    + * Truncation returns a copy of the original time with fields + * smaller than the specified unit set to zero. + * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit + * will set the second-of-minute and nano-of-second field to zero. + *

    + * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time + * units with an exact duration can be used, other units throw an exception. + *

    + * The offset does not affect the calculation and will be the same in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param unit the unit to truncate to, not null + * @return an {@code OffsetTime} based on this time with the time truncated, not null + * @throws DateTimeException if unable to truncate + */ + public OffsetTime truncatedTo(TemporalUnit unit) { + return with(time.truncatedTo(unit), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period added. + *

    + * This method returns a new time based on this time with the specified period added. + * The adder is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #plus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adder the adder to use, not null + * @return an {@code OffsetTime} based on this time with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetTime plus(TemporalAdder adder) { + return (OffsetTime) adder.addTo(this); + } + + /** + * Returns a copy of this time with the specified period added. + *

    + * This method returns a new time based on this time with the specified period added. + * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the period to add, not null + * @return an {@code OffsetTime} based on this time with the specified period added, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + @Override + public OffsetTime plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(time.plus(amountToAdd, unit), offset); + } + return unit.doPlus(this, amountToAdd); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetTime} with the specified period in hours added. + *

    + * This adds the specified number of hours to this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to add, may be negative + * @return an {@code OffsetTime} based on this time with the hours added, not null + */ + public OffsetTime plusHours(long hours) { + return with(time.plusHours(hours), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in minutes added. + *

    + * This adds the specified number of minutes to this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to add, may be negative + * @return an {@code OffsetTime} based on this time with the minutes added, not null + */ + public OffsetTime plusMinutes(long minutes) { + return with(time.plusMinutes(minutes), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in seconds added. + *

    + * This adds the specified number of seconds to this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to add, may be negative + * @return an {@code OffsetTime} based on this time with the seconds added, not null + */ + public OffsetTime plusSeconds(long seconds) { + return with(time.plusSeconds(seconds), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds added. + *

    + * This adds the specified number of nanoseconds to this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to add, may be negative + * @return an {@code OffsetTime} based on this time with the nanoseconds added, not null + */ + public OffsetTime plusNanos(long nanos) { + return with(time.plusNanos(nanos), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this time with the specified period subtracted. + *

    + * This method returns a new time based on this time with the specified period subtracted. + * The subtractor is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #minus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param subtractor the subtractor to use, not null + * @return an {@code OffsetTime} based on this time with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetTime minus(TemporalSubtractor subtractor) { + return (OffsetTime) subtractor.subtractFrom(this); + } + + /** + * Returns a copy of this time with the specified period subtracted. + *

    + * This method returns a new time based on this time with the specified period subtracted. + * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds. + * The unit is responsible for the details of the calculation, including the resolution + * of any edge cases in the calculation. + * The offset is not part of the calculation and will be unchanged in the result. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the period to subtract, not null + * @return an {@code OffsetTime} based on this time with the specified period subtracted, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + @Override + public OffsetTime minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetTime} with the specified period in hours subtracted. + *

    + * This subtracts the specified number of hours from this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to subtract, may be negative + * @return an {@code OffsetTime} based on this time with the hours subtracted, not null + */ + public OffsetTime minusHours(long hours) { + return with(time.minusHours(hours), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in minutes subtracted. + *

    + * This subtracts the specified number of minutes from this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to subtract, may be negative + * @return an {@code OffsetTime} based on this time with the minutes subtracted, not null + */ + public OffsetTime minusMinutes(long minutes) { + return with(time.minusMinutes(minutes), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in seconds subtracted. + *

    + * This subtracts the specified number of seconds from this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to subtract, may be negative + * @return an {@code OffsetTime} based on this time with the seconds subtracted, not null + */ + public OffsetTime minusSeconds(long seconds) { + return with(time.minusSeconds(seconds), offset); + } + + /** + * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds subtracted. + *

    + * This subtracts the specified number of nanoseconds from this time, returning a new time. + * The calculation wraps around midnight. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to subtract, may be negative + * @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null + */ + public OffsetTime minusNanos(long nanos) { + return with(time.minusNanos(nanos), offset); + } + + //----------------------------------------------------------------------- + /** + * Queries this time using the specified query. + *

    + * This queries this time using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.precision()) { + return (R) NANOS; + } else if (query == Queries.offset() || query == Queries.zone()) { + return (R) getOffset(); + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have the same offset and time + * as this object. + *

    + * This returns a temporal object of the same observable type as the input + * with the offset and time changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#OFFSET_SECONDS} and + * {@link ChronoField#NANO_OF_DAY} as the fields. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisOffsetTime.adjustInto(temporal);
    +     *   temporal = temporal.with(thisOffsetTime);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + return temporal + .with(OFFSET_SECONDS, getOffset().getTotalSeconds()) + .with(NANO_OF_DAY, time.toNanoOfDay()); + } + + /** + * Calculates the period between this time and another time in + * terms of the specified unit. + *

    + * This calculates the period between two times in terms of a single unit. + * The start and end points are {@code this} and the specified time. + * The result will be negative if the end is before the start. + * For example, the period in hours between two times can be calculated + * using {@code startTime.periodUntil(endTime, HOURS)}. + *

    + * The {@code Temporal} passed to this method must be an {@code OffsetTime}. + * If the offset differs between the two times, then the specified + * end time is normalized to have the same offset as this time. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two times. + * For example, the period in hours between 11:30Z and 13:29Z will only + * be one hour as it is one minute short of two hours. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, HOURS);   // this method
    +     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, + * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endTime the end time, which must be an {@code OffsetTime}, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this time and the end time + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long periodUntil(Temporal endTime, TemporalUnit unit) { + if (endTime instanceof OffsetTime == false) { + Objects.requireNonNull(endTime, "endTime"); + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + if (unit instanceof ChronoUnit) { + OffsetTime end = (OffsetTime) endTime; + long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow + switch ((ChronoUnit) unit) { + case NANOS: return nanosUntil; + case MICROS: return nanosUntil / 1000; + case MILLIS: return nanosUntil / 1000_000; + case SECONDS: return nanosUntil / NANOS_PER_SECOND; + case MINUTES: return nanosUntil / NANOS_PER_MINUTE; + case HOURS: return nanosUntil / NANOS_PER_HOUR; + case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); + } + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return unit.between(this, endTime).getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns an offset date-time formed from this time at the specified date. + *

    + * This combines this time with the specified date to form an {@code OffsetDateTime}. + * All possible combinations of date and time are valid. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param date the date to combine with, not null + * @return the offset date-time formed from this time and the specified date, not null + */ + public OffsetDateTime atDate(LocalDate date) { + return OffsetDateTime.of(date, time, offset); + } + + //----------------------------------------------------------------------- + /** + * Converts this time to epoch nanos based on 1970-01-01Z. + * + * @return the epoch nanos value + */ + private long toEpochNano() { + long nod = time.toNanoOfDay(); + long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND; + return nod - offsetNanos; + } + + //----------------------------------------------------------------------- + /** + * Compares this {@code OffsetTime} to another time. + *

    + * The comparison is based first on the UTC equivalent instant, then on the local time. + * It is "consistent with equals", as defined by {@link Comparable}. + *

    + * For example, the following is the comparator order: + *

      + *
    1. {@code 10:30+01:00}
    2. + *
    3. {@code 11:00+01:00}
    4. + *
    5. {@code 12:00+02:00}
    6. + *
    7. {@code 11:30+01:00}
    8. + *
    9. {@code 12:00+01:00}
    10. + *
    11. {@code 12:30+01:00}
    12. + *
    + * Values #2 and #3 represent the same instant on the time-line. + * When two values represent the same instant, the local time is compared + * to distinguish them. This step is needed to make the ordering + * consistent with {@code equals()}. + *

    + * To compare the underlying local time of two {@code TemporalAccessor} instances, + * use {@link ChronoField#NANO_OF_DAY} as a comparator. + * + * @param other the other time to compare to, not null + * @return the comparator value, negative if less, positive if greater + * @throws NullPointerException if {@code other} is null + */ + @Override + public int compareTo(OffsetTime other) { + if (offset.equals(other.offset)) { + return time.compareTo(other.time); + } + int compare = Long.compare(toEpochNano(), other.toEpochNano()); + if (compare == 0) { + compare = time.compareTo(other.time); + } + return compare; + } + + //----------------------------------------------------------------------- + /** + * Checks if the instant of this {@code OffsetTime} is after that of the + * specified time applying both times to a common date. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the time. This is equivalent to converting both + * times to an instant using the same date and comparing the instants. + * + * @param other the other time to compare to, not null + * @return true if this is after the instant of the specified time + */ + public boolean isAfter(OffsetTime other) { + return toEpochNano() > other.toEpochNano(); + } + + /** + * Checks if the instant of this {@code OffsetTime} is before that of the + * specified time applying both times to a common date. + *

    + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the instant of the time. This is equivalent to converting both + * times to an instant using the same date and comparing the instants. + * + * @param other the other time to compare to, not null + * @return true if this is before the instant of the specified time + */ + public boolean isBefore(OffsetTime other) { + return toEpochNano() < other.toEpochNano(); + } + + /** + * Checks if the instant of this {@code OffsetTime} is equal to that of the + * specified time applying both times to a common date. + *

    + * This method differs from the comparison in {@link #compareTo} and {@link #equals} + * in that it only compares the instant of the time. This is equivalent to converting both + * times to an instant using the same date and comparing the instants. + * + * @param other the other time to compare to, not null + * @return true if this is equal to the instant of the specified time + */ + public boolean isEqual(OffsetTime other) { + return toEpochNano() == other.toEpochNano(); + } + + //----------------------------------------------------------------------- + /** + * Checks if this time is equal to another time. + *

    + * The comparison is based on the local-time and the offset. + * To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}. + *

    + * Only objects of type {@code OffsetTime} are compared, other types return false. + * To compare the underlying local time of two {@code TemporalAccessor} instances, + * use {@link ChronoField#NANO_OF_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OffsetTime) { + OffsetTime other = (OffsetTime) obj; + return time.equals(other.time) && offset.equals(other.offset); + } + return false; + } + + /** + * A hash code for this time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return time.hashCode() ^ offset.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}. + *

    + * The output will be one of the following ISO-8601 formats: + *

      + *
    • {@code HH:mmXXXXX}
    • + *
    • {@code HH:mm:ssXXXXX}
    • + *
    • {@code HH:mm:ss.SSSXXXXX}
    • + *
    • {@code HH:mm:ss.SSSSSSXXXXX}
    • + *
    • {@code HH:mm:ss.SSSSSSSSSXXXXX}
    • + *

    + * The format used will be the shortest that outputs the full value of + * the time where the omitted parts are implied to be zero. + * + * @return a string representation of this time, not null + */ + @Override + public String toString() { + return time.toString() + offset.toString(); + } + + /** + * Outputs this time as a {@code String} using the formatter. + *

    + * This time will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted time string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + // ----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(2);  // identifies this as a OffsetDateTime
    +     *  out.writeObject(time);
    +     *  out.writeObject(offset);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.OFFSET_TIME_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(time); + out.writeObject(offset); + } + + static OffsetTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + LocalTime time = (LocalTime) in.readObject(); + ZoneOffset offset = (ZoneOffset) in.readObject(); + return OffsetTime.of(time, offset); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/Queries.java b/jdk/src/share/classes/java/time/temporal/Queries.java new file mode 100644 index 00000000000..74b8f1adf85 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Queries.java @@ -0,0 +1,302 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import static java.time.temporal.ChronoField.OFFSET_SECONDS; + +import java.time.ZoneId; +import java.time.ZoneOffset; + +/** + * Common implementations of {@code TemporalQuery}. + *

    + * This class provides common implementations of {@link TemporalQuery}. + * These queries are primarily used as optimizations, allowing the internals + * of other objects to be extracted effectively. Note that application code + * can also use the {@code from(TemporalAccessor)} method on most temporal + * objects as a method reference matching the query interface, such as + * {@code LocalDate::from} and {@code ZoneId::from}. + *

    + * There are two equivalent ways of using a {@code TemporalQuery}. + * The first is to invoke the method on the interface directly. + * The second is to use {@link TemporalAccessor#query(TemporalQuery)}: + *

    + *   // these two lines are equivalent, but the second approach is recommended
    + *   dateTime = query.queryFrom(dateTime);
    + *   dateTime = dateTime.query(query);
    + * 
    + * It is recommended to use the second approach, {@code query(TemporalQuery)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * This is a thread-safe utility class. + * All returned adjusters are immutable and thread-safe. + * + * @since 1.8 + */ +public final class Queries { + // note that it is vital that each method supplies a constant, not a + // calculated value, as they will be checked for using == + // it is also vital that each constant is different (due to the == checking) + // as such, alterations to use lambdas must be done with extreme care + + /** + * Private constructor since this is a utility class. + */ + private Queries() { + } + + //----------------------------------------------------------------------- + // special constants should be used to extract information from a TemporalAccessor + // that cannot be derived in other ways + // Javadoc added here, so as to pretend they are more normal than they really are + + /** + * A strict query for the {@code ZoneId}. + *

    + * This queries a {@code TemporalAccessor} for the zone. + * The zone is only returned if the date-time conceptually contains a {@code ZoneId}. + * It will not be returned if the date-time only conceptually has an {@code ZoneOffset}. + * Thus a {@link java.time.ZonedDateTime ZonedDateTime} will return the result of + * {@code getZone()}, but an {@link java.time.temporal.OffsetDateTime OffsetDateTime} will + * return null. + *

    + * In most cases, applications should use {@link #ZONE} as this query is too strict. + *

    + * The result from JDK classes implementing {@code TemporalAccessor} is as follows:
    + * {@code LocalDate} returns null
    + * {@code LocalTime} returns null
    + * {@code LocalDateTime} returns null
    + * {@code ZonedDateTime} returns the associated zone
    + * {@code OffsetDate} returns null
    + * {@code OffsetTime} returns null
    + * {@code OffsetDateTime} returns null
    + * {@code ChronoLocalDate} returns null
    + * {@code ChronoLocalDateTime} returns null
    + * {@code ChronoZonedDateTime} returns the associated zone
    + * {@code Era} returns null
    + * {@code DayOfWeek} returns null
    + * {@code Month} returns null
    + * {@code Year} returns null
    + * {@code YearMonth} returns null
    + * {@code MonthDay} returns null
    + * {@code ZoneOffset} returns null
    + * {@code Instant} returns null
    + * @return a ZoneId, may be null + */ + public static final TemporalQuery zoneId() { + return ZONE_ID; + } + static final TemporalQuery ZONE_ID = new TemporalQuery() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + return temporal.query(this); + } + }; + + /** + * A query for the {@code Chrono}. + *

    + * This queries a {@code TemporalAccessor} for the chronology. + * If the target {@code TemporalAccessor} represents a date, or part of a date, + * then it should return the chronology that the date is expressed in. + * As a result of this definition, objects only representing time, such as + * {@code LocalTime}, will return null. + *

    + * The result from JDK classes implementing {@code TemporalAccessor} is as follows:
    + * {@code LocalDate} returns {@code ISOChrono.INSTANCE}
    + * {@code LocalTime} returns null (does not represent a date)
    + * {@code LocalDateTime} returns {@code ISOChrono.INSTANCE}
    + * {@code ZonedDateTime} returns {@code ISOChrono.INSTANCE}
    + * {@code OffsetDate} returns {@code ISOChrono.INSTANCE}
    + * {@code OffsetTime} returns null (does not represent a date)
    + * {@code OffsetDateTime} returns {@code ISOChrono.INSTANCE}
    + * {@code ChronoLocalDate} returns the associated chronology
    + * {@code ChronoLocalDateTime} returns the associated chronology
    + * {@code ChronoZonedDateTime} returns the associated chronology
    + * {@code Era} returns the associated chronology
    + * {@code DayOfWeek} returns null (shared across chronologies)
    + * {@code Month} returns {@code ISOChrono.INSTANCE}
    + * {@code Year} returns {@code ISOChrono.INSTANCE}
    + * {@code YearMonth} returns {@code ISOChrono.INSTANCE}
    + * {@code MonthDay} returns null {@code ISOChrono.INSTANCE}
    + * {@code ZoneOffset} returns null (does not represent a date)
    + * {@code Instant} returns null (does not represent a date)
    + *

    + * The method {@link Chrono#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code Chrono::from}. + * That method is equivalent to this query, except that it throws an + * exception if a chronology cannot be obtained. + * @return a Chrono, may be null + */ + public static final TemporalQuery> chrono() { + return CHRONO; + } + static final TemporalQuery> CHRONO = new TemporalQuery>() { + @Override + public Chrono queryFrom(TemporalAccessor temporal) { + return temporal.query(this); + } + }; + + /** + * A query for the smallest supported unit. + *

    + * This queries a {@code TemporalAccessor} for the time precision. + * If the target {@code TemporalAccessor} represents a consistent or complete date-time, + * date or time then this must return the smallest precision actually supported. + * Note that fields such as {@code NANO_OF_DAY} and {@code NANO_OF_SECOND} + * are defined to always return ignoring the precision, thus this is the only + * way to find the actual smallest supported unit. + * For example, were {@code GregorianCalendar} to implement {@code TemporalAccessor} + * it would return a precision of {@code MILLIS}. + *

    + * The result from JDK classes implementing {@code TemporalAccessor} is as follows:
    + * {@code LocalDate} returns {@code DAYS}
    + * {@code LocalTime} returns {@code NANOS}
    + * {@code LocalDateTime} returns {@code NANOS}
    + * {@code ZonedDateTime} returns {@code NANOS}
    + * {@code OffsetDate} returns {@code DAYS}
    + * {@code OffsetTime} returns {@code NANOS}
    + * {@code OffsetDateTime} returns {@code NANOS}
    + * {@code ChronoLocalDate} returns {@code DAYS}
    + * {@code ChronoLocalDateTime} returns {@code NANOS}
    + * {@code ChronoZonedDateTime} returns {@code NANOS}
    + * {@code Era} returns {@code ERAS}
    + * {@code DayOfWeek} returns {@code DAYS}
    + * {@code Month} returns {@code MONTHS}
    + * {@code Year} returns {@code YEARS}
    + * {@code YearMonth} returns {@code MONTHS}
    + * {@code MonthDay} returns null (does not represent a complete date or time)
    + * {@code ZoneOffset} returns null (does not represent a date or time)
    + * {@code Instant} returns {@code NANOS}
    + * @return a ChronoUnit, may be null + */ + public static final TemporalQuery precision() { + return PRECISION; + } + static final TemporalQuery PRECISION = new TemporalQuery() { + @Override + public ChronoUnit queryFrom(TemporalAccessor temporal) { + return temporal.query(this); + } + }; + + //----------------------------------------------------------------------- + // non-special constants are standard queries that derive information from other information + /** + * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. + *

    + * This queries a {@code TemporalAccessor} for the zone. + * It first tries to obtain the zone, using {@link #zoneId()}. + * If that is not found it tries to obtain the {@link #offset()}. + *

    + * In most cases, applications should use this query rather than {@code #zoneId()}. + *

    + * This query examines the {@link java.time.temporal.ChronoField#OFFSET_SECONDS offset-seconds} + * field and uses it to create a {@code ZoneOffset}. + *

    + * The method {@link ZoneId#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code ZoneId::from}. + * That method is equivalent to this query, except that it throws an + * exception if a zone cannot be obtained. + * @return a ZoneId, may be null + */ + public static final TemporalQuery zone() { + return ZONE; + } + static final TemporalQuery ZONE = new TemporalQuery() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + ZoneId zone = temporal.query(ZONE_ID); + return (zone != null ? zone : temporal.query(OFFSET)); + } + }; + + /** + * A query for the {@code ZoneOffset}. + *

    + * This queries a {@code TemporalAccessor} for the offset. + *

    + * This query examines the {@link java.time.temporal.ChronoField#OFFSET_SECONDS offset-seconds} + * field and uses it to create a {@code ZoneOffset}. + *

    + * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code ZoneOffset::from}. + * That method is equivalent to this query, except that it throws an + * exception if an offset cannot be obtained. + * @return a ZoneOffset, may be null + */ + public static final TemporalQuery offset() { + return OFFSET; + } + static final TemporalQuery OFFSET = new TemporalQuery() { + @Override + public ZoneOffset queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(OFFSET_SECONDS)) { + return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + } + return null; + } + }; + +} diff --git a/jdk/src/share/classes/java/time/temporal/Ser.java b/jdk/src/share/classes/java/time/temporal/Ser.java new file mode 100644 index 00000000000..2f182e0439b --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Ser.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. 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) 2011-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 java.time.temporal; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StreamCorruptedException; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * The shared serialization delegate for this package. + * + *

    Implementation notes

    + * This class wraps the object being serialized, and takes a byte representing the type of the class to + * be serialized. This byte can also be used for versioning the serialization format. In this case another + * byte flag would be used in order to specify an alternative version of the type format. + * For example {@code CHRONO_TYPE_VERSION_2 = 21} + *

    + * In order to serialise the object it writes its byte and then calls back to the appropriate class where + * the serialisation is performed. In order to deserialise the object it read in the type byte, switching + * in order to select which class to call back into. + *

    + * The serialisation format is determined on a per class basis. In the case of field based classes each + * of the fields is written out with an appropriate size format in descending order of the field's size. For + * example in the case of {@link LocalDate} year is written before month. Composite classes, such as + * {@link LocalDateTime} are serialised as one object. Enum classes are serialised using the index of their + * element. + *

    + * This class is mutable and should be created once per serialization. + * + * @serial include + * @since 1.8 + */ +final class Ser implements Externalizable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -6103370247208168577L; + + static final byte OFFSET_DATE_TYPE = 1; + static final byte OFFSET_TIME_TYPE = 2; + static final byte OFFSET_DATE_TIME_TYPE = 3; + static final byte YEAR_TYPE = 4; + static final byte YEAR_MONTH_TYPE = 5; + static final byte MONTH_DAY_TYPE = 6; + static final byte CHRONO_TYPE = 7; + static final byte CHRONO_LOCAL_DATE_TIME_TYPE = 8; + static final byte CHRONO_ZONE_DATE_TIME_TYPE = 9; + static final byte SIMPLE_PERIOD_TYPE = 10; + + /** The type being serialized. */ + private byte type; + /** The object being serialized. */ + private Object object; + + /** + * Constructor for deserialization. + */ + public Ser() { + } + + /** + * Creates an instance for serialization. + * + * @param type the type + * @param object the object + */ + Ser(byte type, Object object) { + this.type = type; + this.object = object; + } + + //----------------------------------------------------------------------- + /** + * Implements the {@code Externalizable} interface to write the object. + * + * @param out the data stream to write to, not null + */ + @Override + public void writeExternal(ObjectOutput out) throws IOException { + writeInternal(type, object, out); + } + + private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException { + out.writeByte(type); + switch (type) { + case OFFSET_DATE_TYPE: + ((OffsetDate) object).writeExternal(out); + break; + case OFFSET_TIME_TYPE: + ((OffsetTime) object).writeExternal(out); + break; + case OFFSET_DATE_TIME_TYPE: + ((OffsetDateTime) object).writeExternal(out); + break; + case YEAR_TYPE: + ((Year) object).writeExternal(out); + break; + case YEAR_MONTH_TYPE: + ((YearMonth) object).writeExternal(out); + break; + case MONTH_DAY_TYPE: + ((MonthDay) object).writeExternal(out); + break; + case CHRONO_TYPE: + ((Chrono) object).writeExternal(out); + break; + case CHRONO_LOCAL_DATE_TIME_TYPE: + ((ChronoLocalDateTimeImpl) object).writeExternal(out); + break; + case CHRONO_ZONE_DATE_TIME_TYPE: + ((ChronoZonedDateTimeImpl) object).writeExternal(out); + break; + case SIMPLE_PERIOD_TYPE: + ((SimplePeriod) object).writeExternal(out); + break; + default: + throw new InvalidClassException("Unknown serialized type"); + } + } + + //----------------------------------------------------------------------- + /** + * Implements the {@code Externalizable} interface to read the object. + * + * @param in the data to read, not null + */ + @Override + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + type = in.readByte(); + object = readInternal(type, in); + } + + static Object read(ObjectInput in) throws IOException, ClassNotFoundException { + byte type = in.readByte(); + return readInternal(type, in); + } + + private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException { + switch (type) { + case OFFSET_DATE_TYPE: return OffsetDate.readExternal(in); + case OFFSET_TIME_TYPE: return OffsetTime.readExternal(in); + case OFFSET_DATE_TIME_TYPE: return OffsetDateTime.readExternal(in); + case YEAR_TYPE: return Year.readExternal(in); + case YEAR_MONTH_TYPE: return YearMonth.readExternal(in); + case MONTH_DAY_TYPE: return MonthDay.readExternal(in); + case CHRONO_TYPE: return Chrono.readExternal(in); + case CHRONO_LOCAL_DATE_TIME_TYPE: return ChronoLocalDateTimeImpl.readExternal(in); + case CHRONO_ZONE_DATE_TIME_TYPE: return ChronoZonedDateTimeImpl.readExternal(in); + case SIMPLE_PERIOD_TYPE: return SimplePeriod.readExternal(in); + default: throw new StreamCorruptedException("Unknown serialized type"); + } + } + + /** + * Returns the object that will replace this one. + * + * @return the read object, should never be null + */ + private Object readResolve() { + return object; + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/SimplePeriod.java b/jdk/src/share/classes/java/time/temporal/SimplePeriod.java new file mode 100644 index 00000000000..5eb60f5c903 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/SimplePeriod.java @@ -0,0 +1,348 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.DateTimeException; +import java.util.Objects; + +/** + * A period of time, measured as an amount of a single unit, such as '3 Months'. + *

    + * A {@code SimplePeriod} represents an amount of time measured in terms of a + * single {@link TemporalUnit unit}. Any unit may be used with this class. + * An alternative period implementation is {@link java.time.Period Period}, which + * allows a combination of date and time units. + *

    + * This class is the return type from {@link TemporalUnit#between}. + * It can be used more generally, but is designed to enable the following code: + *

    + *  date = date.minus(MONTHS.between(start, end));
    + * 
    + * The unit determines which calendar systems it can be added to. + *

    + * The period is modeled as a directed amount of time, meaning that the period may + * be negative. See {@link #abs()} to ensure the period is positive. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe, providing that the unit is immutable, + * which it is required to be. + * + * @since 1.8 + */ +public final class SimplePeriod + implements TemporalAdder, TemporalSubtractor, Comparable, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 3752975649629L; + + /** + * The amount of the unit. + */ + private final long amount; + /** + * The unit. + */ + private final TemporalUnit unit; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code SimplePeriod} from a period in the specified unit. + *

    + * The parameters represent the two parts of a phrase like '6 Days'. For example: + *

    +     *  SimplePeriod.of(3, SECONDS);
    +     *  SimplePeriod.of(5, YEARS);
    +     * 
    + * + * @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, not null + * @return the period, not null + */ + public static SimplePeriod of(long amount, TemporalUnit unit) { + Objects.requireNonNull(unit, "unit"); + return new SimplePeriod(amount, unit); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @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, not null + */ + SimplePeriod(long amount, TemporalUnit unit) { + this.amount = amount; + this.unit = unit; + } + + //----------------------------------------------------------------------- + /** + * Gets the amount of this period. + *

    + * In the phrase "2 Months", the amount is 2. + * + * @return the amount of the period, may be negative + */ + public long getAmount() { + return amount; + } + + /** + * Gets the unit of this period. + *

    + * In the phrase "2 Months", the unit is "Months". + * + * @return the unit of the period, not null + */ + public TemporalUnit getUnit() { + return unit; + } + + //------------------------------------------------------------------------- + /** + * Adds this period to the specified temporal object. + *

    + * This returns a temporal object of the same observable type as the input + * with this period added. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#plus(TemporalAdder)}. + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = thisPeriod.addTo(dateTime);
    +     *   dateTime = dateTime.plus(thisPeriod);
    +     * 
    + *

    + * The calculation is equivalent to invoking {@link Temporal#plus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to add + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal addTo(Temporal temporal) { + return temporal.plus(amount, unit); + } + + /** + * Subtracts this period to the specified temporal object. + *

    + * This returns a temporal object of the same observable type as the input + * with this period subtracted. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#plus(TemporalAdder)}. + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = thisPeriod.subtractFrom(dateTime);
    +     *   dateTime = dateTime.minus(thisPeriod);
    +     * 
    + *

    + * The calculation is equivalent to invoking {@link Temporal#minus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to subtract + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal subtractFrom(Temporal temporal) { + return temporal.minus(amount, unit); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this period with a positive amount. + *

    + * This returns a period with the absolute value of the amount and the same unit. + * If the amount of this period is positive or zero, then this period is returned. + * If the amount of this period is negative, then a period with the negated + * amount is returned. If the amount equals {@code Long.MIN_VALUE}, + * an {@code ArithmeticException} is thrown + *

    + * This is useful to convert the result of {@link TemporalUnit#between} to + * a positive amount when you do not know which date is the earlier and + * which is the later. + * + * @return a period with a positive amount and the same unit, not null + * @throws ArithmeticException if the amount is {@code Long.MIN_VALUE} + */ + public SimplePeriod abs() { + if (amount == Long.MIN_VALUE) { + throw new ArithmeticException("Unable to call abs() on MIN_VALUE"); + } + return (amount >= 0 ? this : new SimplePeriod(-amount, unit)); + } + + //----------------------------------------------------------------------- + /** + * Compares this {@code SimplePeriod} to another period. + *

    + * The comparison is based on the amount within the unit. + * Only two periods with the same unit can be compared. + * + * @param other the other period to compare to, not null + * @return the comparator value, negative if less, positive if greater + * @throws IllegalArgumentException if the units do not match + */ + @Override + public int compareTo(SimplePeriod other) { + if (unit.equals(other.unit) == false) { + throw new IllegalArgumentException("Unable to compare periods with different units"); + } + return Long.compare(amount, other.amount); + } + + //----------------------------------------------------------------------- + /** + * Checks if this period is equal to another period. + *

    + * The comparison is based on the amount and unit. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other period + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof SimplePeriod) { + SimplePeriod other = (SimplePeriod) obj; + return amount == other.amount && unit.equals(other.unit); + } + return false; + } + + /** + * A hash code for this period. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return unit.hashCode() ^ (int) (amount ^ (amount >>> 32)); + } + + //----------------------------------------------------------------------- + /** + * Outputs this period as a {@code String}, such as {@code 2 Months}. + *

    + * The string consists of the amount, then a space, then the unit name. + * + * @return a string representation of this period, not null + */ + @Override + public String toString() { + return amount + " " + unit.getName(); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(10);  // identifies this as a SimplePeriod
    +     *  out.writeLong(amount);
    +     *  out.writeObject(unit);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.SIMPLE_PERIOD_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(ObjectOutput out) throws IOException { + out.writeLong(amount); + out.writeObject(unit); + } + + static SimplePeriod readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + long amount = in.readLong(); + TemporalUnit unit = (TemporalUnit) in.readObject(); + return SimplePeriod.of(amount, unit); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/Temporal.java b/jdk/src/share/classes/java/time/temporal/Temporal.java new file mode 100644 index 00000000000..0eddf27b964 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Temporal.java @@ -0,0 +1,410 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.ZoneId; + +/** + * Framework-level interface defining read-write access to a temporal object, + * such as a date, time, offset or some combination of these. + *

    + * This is the base interface type for date, time and offset objects that + * are complete enough to be manipulated using plus and minus. + * It is implemented by those classes that can provide and manipulate information + * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}. + * See {@link TemporalAccessor} for the read-only version of this interface. + *

    + * Most date and time information can be represented as a number. + * These are modeled using {@code TemporalField} with the number held using + * a {@code long} to handle large values. Year, month and day-of-month are + * simple examples of fields, but they also include instant and offsets. + * See {@link ChronoField} for the standard set of fields. + *

    + * Two pieces of date/time information cannot be represented by numbers, + * the {@linkplain Chrono chronology} and the {@linkplain ZoneId time-zone}. + * These can be accessed via {@link #query(TemporalQuery) queries} using + * the static methods defined on {@link Queries}. + *

    + * This interface is a framework-level interface that should not be widely + * used in application code. Instead, applications should create and pass + * around instances of concrete types, such as {@code LocalDate}. + * There are many reasons for this, part of which is that implementations + * of this interface may be in calendar systems other than ISO. + * See {@link ChronoLocalDate} for a fuller discussion of the issues. + * + *

    When to implement

    + *

    + * A class should implement this interface if it meets three criteria: + *

      + *
    • it provides access to date/time/offset information, as per {@code TemporalAccessor} + *
    • the set of fields are contiguous from the largest to the smallest + *
    • the set of fields are complete, such that no other field is needed to define the + * valid range of values for the fields that are represented + *

    + *

    + * Four examples make this clear: + *

      + *
    • {@code LocalDate} implements this interface as it represents a set of fields + * that are contiguous from days to forever and require no external information to determine + * the validity of each date. It is therefore able to implement plus/minus correctly. + *
    • {@code LocalTime} implements this interface as it represents a set of fields + * that are contiguous from nanos to within days and require no external information to determine + * validity. It is able to implement plus/minus correctly, by wrapping around the day. + *
    • {@code MonthDay}, the combination of month-of-year and day-of-month, does not implement + * this interface. While the combination is contiguous, from days to months within years, + * the combination does not have sufficient information to define the valid range of values + * for day-of-month. As such, it is unable to implement plus/minus correctly. + *
    • The combination day-of-week and day-of-month ("Friday the 13th") should not implement + * this interface. It does not represent a contiguous set of fields, as days to weeks overlaps + * days to months. + *

    + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * All implementations must be {@link Comparable}. + * + * @since 1.8 + */ +public interface Temporal extends TemporalAccessor { + + /** + * Returns an adjusted object of the same type as this object with the adjustment made. + *

    + * This adjusts this date-time according to the rules of the specified adjuster. + * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the date to the last day of the month. + * A selection of common adjustments is provided in {@link Adjusters}. + * These include finding the "last day of the month" and "next Wednesday". + * The adjuster is responsible for handling special cases, such as the varying + * lengths of month and leap years. + *

    + * Some example code indicating how and why this method is used: + *

    +     *  date = date.with(Month.JULY);        // most key classes implement TemporalAdjuster
    +     *  date = date.with(lastDayOfMonth());  // static import from Adjusters
    +     *  date = date.with(next(WEDNESDAY));   // static import from Adjusters and DayOfWeek
    +     * 
    + * + *

    Specification for implementors

    + * Implementations must not alter either this object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return adjuster.adjustInto(this);
    +     * 
    + * + * @param adjuster the adjuster to use, not null + * @return an object of the same type with the specified adjustment made, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + public default Temporal with(TemporalAdjuster adjuster) { + return adjuster.adjustInto(this); + } + + /** + * Returns an object of the same type as this object with the specified field altered. + *

    + * This returns a new object based on this one with the value for the specified field changed. + * For example, on a {@code LocalDate}, this could be used to set the year, month or day-of-month. + * The returned object will have the same observable type as this object. + *

    + * In some cases, changing a field is not fully defined. For example, if the target object is + * a date representing the 31st January, then changing the month to February would be unclear. + * In cases like this, the field is responsible for resolving the result. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + * + *

    Specification for implementors

    + * Implementations must check and handle all fields defined in {@link ChronoField}. + * If the field is supported, then the adjustment must be performed. + * If unsupported, then a {@code DateTimeException} must be thrown. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the first argument. + *

    + * Implementations must not alter either this object or the specified temporal object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an object of the same type with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + Temporal with(TemporalField field, long newValue); + + //----------------------------------------------------------------------- + /** + * Returns an object of the same type as this object with an amount added. + *

    + * This adjusts this temporal, adding according to the rules of the specified adder. + * The adder is typically a {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface, such as {@link java.time.Duration}. + *

    + * Some example code indicating how and why this method is used: + *

    +     *  date = date.plus(period);                      // add a Period instance
    +     *  date = date.plus(duration);                    // add a Duration instance
    +     *  date = date.plus(MONTHS.between(start, end));  // static import of MONTHS field
    +     *  date = date.plus(workingDays(6));              // example user-written workingDays method
    +     * 
    + *

    + * Note that calling {@code plus} followed by {@code minus} is not guaranteed to + * return the same date-time. + * + *

    Specification for implementors

    + * Implementations must not alter either this object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return adder.addTo(this);
    +     * 
    + * + * @param adder the adder to use, not null + * @return an object of the same type with the specified adjustment made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + public default Temporal plus(TemporalAdder adder) { + return adder.addTo(this); + } + + /** + * Returns an object of the same type as this object with the specified period added. + *

    + * This method returns a new object based on this one with the specified period added. + * For example, on a {@code LocalDate}, this could be used to add a number of years, months or days. + * The returned object will have the same observable type as this object. + *

    + * In some cases, changing a field is not fully defined. For example, if the target object is + * a date representing the 31st January, then adding one month would be unclear. + * In cases like this, the field is responsible for resolving the result. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + *

    + * If the implementation represents a date-time that has boundaries, such as {@code LocalTime}, + * then the permitted units must include the boundary unit, but no multiples of the boundary unit. + * For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}. + * + *

    Specification for implementors

    + * Implementations must check and handle all units defined in {@link ChronoUnit}. + * If the unit is supported, then the addition must be performed. + * If unsupported, then a {@code DateTimeException} must be thrown. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.doPlus(Temporal, long)} + * passing {@code this} as the first argument. + *

    + * Implementations must not alter either this object or the specified temporal object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + * + * @param amountToAdd the amount of the specified unit to add, may be negative + * @param unit the unit of the period to add, not null + * @return an object of the same type with the specified period added, not null + * @throws DateTimeException if the unit cannot be added + * @throws ArithmeticException if numeric overflow occurs + */ + Temporal plus(long amountToAdd, TemporalUnit unit); + + //----------------------------------------------------------------------- + /** + * Returns an object of the same type as this object with an amount subtracted. + *

    + * This adjusts this temporal, subtracting according to the rules of the specified subtractor. + * The subtractor is typically a {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface, such as {@link java.time.Duration}. + *

    + * Some example code indicating how and why this method is used: + *

    +     *  date = date.minus(period);                      // subtract a Period instance
    +     *  date = date.minus(duration);                    // subtract a Duration instance
    +     *  date = date.minus(MONTHS.between(start, end));  // static import of MONTHS field
    +     *  date = date.minus(workingDays(6));              // example user-written workingDays method
    +     * 
    + *

    + * Note that calling {@code plus} followed by {@code minus} is not guaranteed to + * return the same date-time. + * + *

    Specification for implementors

    + * Implementations must not alter either this object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return subtractor.subtractFrom(this);
    +     * 
    + * + * @param subtractor the subtractor to use, not null + * @return an object of the same type with the specified adjustment made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + public default Temporal minus(TemporalSubtractor subtractor) { + return subtractor.subtractFrom(this); + } + + /** + * Returns an object of the same type as this object with the specified period subtracted. + *

    + * This method returns a new object based on this one with the specified period subtracted. + * For example, on a {@code LocalDate}, this could be used to subtract a number of years, months or days. + * The returned object will have the same observable type as this object. + *

    + * In some cases, changing a field is not fully defined. For example, if the target object is + * a date representing the 31st March, then subtracting one month would be unclear. + * In cases like this, the field is responsible for resolving the result. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + *

    + * If the implementation represents a date-time that has boundaries, such as {@code LocalTime}, + * then the permitted units must include the boundary unit, but no multiples of the boundary unit. + * For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}. + * + *

    Specification for implementors

    + * Implementations must behave in a manor equivalent to the default method behavior. + *

    + * Implementations must not alter either this object or the specified temporal object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return (amountToSubtract == Long.MIN_VALUE ?
    +     *      plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
    +     * 
    + * + * @param amountToSubtract the amount of the specified unit to subtract, may be negative + * @param unit the unit of the period to subtract, not null + * @return an object of the same type with the specified period subtracted, not null + * @throws DateTimeException if the unit cannot be subtracted + * @throws ArithmeticException if numeric overflow occurs + */ + public default Temporal minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Calculates the period between this temporal and another temporal in + * terms of the specified unit. + *

    + * This calculates the period between two temporals in terms of a single unit. + * The start and end points are {@code this} and the specified temporal. + * The result will be negative if the end is before the start. + * For example, the period in hours between two temporal objects can be + * calculated using {@code startTime.periodUntil(endTime, HOURS)}. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two temporals. + * For example, the period in hours between the times 11:30 and 13:29 + * will only be one hour as it is one minute short of two hours. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, HOURS);   // this method
    +     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
    +     * 
    + * + *

    Specification for implementors

    + * Implementations must begin by checking to ensure that the input temporal + * object is of the same observable type as the implementation. + * They must then perform the calculation for all instances of {@link ChronoUnit}. + * A {@code DateTimeException} must be thrown for {@code ChronoUnit} + * instances that are unsupported. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * In summary, implementations must behave in a manner equivalent to this code: + *

    +     *  // check input temporal is the same type as this class
    +     *  if (unit instanceof ChronoUnit) {
    +     *    // if unit is supported, then calculate and return result
    +     *    // else throw DateTimeException for unsupported units
    +     *  }
    +     *  return unit.between(this, endTime).getAmount();
    +     * 
    + *

    + * The target object must not be altered by this method. + * + * @param endTemporal the end temporal, of the same type as this object, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this and the end + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + long periodUntil(Temporal endTemporal, TemporalUnit unit); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java new file mode 100644 index 00000000000..2f88fa74c7a --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java @@ -0,0 +1,292 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.ZoneId; + +/** + * Framework-level interface defining read-only access to a temporal object, + * such as a date, time, offset or some combination of these. + *

    + * This is the base interface type for date, time and offset objects. + * It is implemented by those classes that can provide information + * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}. + *

    + * Most date and time information can be represented as a number. + * These are modeled using {@code TemporalField} with the number held using + * a {@code long} to handle large values. Year, month and day-of-month are + * simple examples of fields, but they also include instant and offsets. + * See {@link ChronoField} for the standard set of fields. + *

    + * Two pieces of date/time information cannot be represented by numbers, + * the {@linkplain Chrono chronology} and the {@linkplain ZoneId time-zone}. + * These can be accessed via {@link #query(TemporalQuery) queries} using + * the static methods defined on {@link Queries}. + *

    + * A sub-interface, {@link Temporal}, extends this definition to one that also + * supports adjustment and manipulation on more complete temporal objects. + *

    + * This interface is a framework-level interface that should not be widely + * used in application code. Instead, applications should create and pass + * around instances of concrete types, such as {@code LocalDate}. + * There are many reasons for this, part of which is that implementations + * of this interface may be in calendar systems other than ISO. + * See {@link ChronoLocalDate} for a fuller discussion of the issues. + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalAccessor { + + /** + * Checks if the specified field is supported. + *

    + * This checks if the date-time can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get} + * methods will throw an exception. + * + *

    Specification for implementors

    + * Implementations must check and handle all fields defined in {@link ChronoField}. + * If the field is supported, then true is returned, otherwise false + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + *

    + * Implementations must not alter either this object. + * + * @param field the field to check, null returns false + * @return true if this date-time can be queried for the field, false if not + */ + boolean isSupported(TemporalField field); + + /** + * Gets the range of valid values for the specified field. + *

    + * All fields can be expressed as a {@code long} integer. + * This method returns an object that describes the valid range for that value. + * The value of this temporal object is used to enhance the accuracy of the returned range. + * If the date-time cannot return the range, because the field is unsupported or for + * some other reason, an exception will be thrown. + *

    + * Note that the result only describes the minimum and maximum valid values + * and it is important not to read too much into them. For example, there + * could be values within the range that are invalid for the field. + * + *

    Specification for implementors

    + * Implementations must check and handle all fields defined in {@link ChronoField}. + * If the field is supported, then the range of the field must be returned. + * If unsupported, then a {@code DateTimeException} must be thrown. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessorl)} + * passing {@code this} as the argument. + *

    + * Implementations must not alter either this object. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  if (field instanceof ChronoField) {
    +     *    if (isSupported(field)) {
    +     *      return field.range();
    +     *    }
    +     *    throw new DateTimeException("Unsupported field: " + field.getName());
    +     *  }
    +     *  return field.doRange(this);
    +     * 
    + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + public default ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (isSupported(field)) { + return field.range(); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doRange(this); + } + + /** + * Gets the value of the specified field as an {@code int}. + *

    + * This queries the date-time for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If the date-time cannot return the value, because the field is unsupported or for + * some other reason, an exception will be thrown. + * + *

    Specification for implementors

    + * Implementations must check and handle all fields defined in {@link ChronoField}. + * If the field is supported and has an {@code int} range, then the value of + * the field must be returned. + * If unsupported, then a {@code DateTimeException} must be thrown. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. + *

    + * Implementations must not alter either this object. + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return range(field).checkValidIntValue(getLong(field), field);
    +     * 
    + * + * @param field the field to get, not null + * @return the value for the field, within the valid range of values + * @throws DateTimeException if a value for the field cannot be obtained + * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} + * @throws DateTimeException if the value is outside the range of valid values for the field + * @throws ArithmeticException if numeric overflow occurs + */ + public default int get(TemporalField field) { + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field as a {@code long}. + *

    + * This queries the date-time for the value for the specified field. + * The returned value may be outside the valid range of values for the field. + * If the date-time cannot return the value, because the field is unsupported or for + * some other reason, an exception will be thrown. + * + *

    Specification for implementors

    + * Implementations must check and handle all fields defined in {@link ChronoField}. + * If the field is supported, then the value of the field must be returned. + * If unsupported, then a {@code DateTimeException} must be thrown. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. + *

    + * Implementations must not alter either this object. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + long getLong(TemporalField field); + + /** + * Queries this date-time. + *

    + * This queries this date-time using the specified query strategy object. + *

    + * Queries are a key tool for extracting information from date-times. + * They exists to externalize the process of querying, permitting different + * approaches, as per the strategy design pattern. + * Examples might be a query that checks if the date is the day before February 29th + * in a leap year, or calculates the number of days to your next birthday. + *

    + * The most common query implementations are method references, such as + * {@code LocalDate::from} and {@code ZoneId::from}. + * Further implementations are on {@link Queries}. + * Queries may also be defined by applications. + * + *

    Specification for implementors

    + * The default implementation must behave equivalent to this code: + *
    +     *  if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
    +     *    return null;
    +     *  }
    +     *  return query.queryFrom(this);
    +     * 
    + * Future versions are permitted to add further queries to the if statement. + *

    + * All classes implementing this interface and overriding this method must call + * {@code TemporalAccessor.super.query(query)}. JDK classes may avoid calling + * super if they provide behavior equivalent to the default behaviour, however + * non-JDK classes may not utilize this optimization and must call {@code super}. + *

    + * If the implementation can supply a value for one of the queries listed in the + * if statement of the default implementation, then it must do so. + * For example, an application-defined {@code HourMin} class storing the hour + * and minute must override this method as follows: + *

    +     *  if (query == Queries.precision()) {
    +     *    return MINUTES;
    +     *  }
    +     *  return TemporalAccessor.super.query(query);
    +     * 
    + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query + * @throws ArithmeticException if numeric overflow occurs + */ + public default R query(TemporalQuery query) { + if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) { + return null; + } + return query.queryFrom(this); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAdder.java b/jdk/src/share/classes/java/time/temporal/TemporalAdder.java new file mode 100644 index 00000000000..fad2db42abb --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalAdder.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Period; + +/** + * Strategy for adding to a temporal object. + *

    + * Adders are a key tool for modifying temporal objects. + * They exist to externalize the process of addition, permitting different + * approaches, as per the strategy design pattern. + *

    + * There are two equivalent ways of using a {@code TemporalAdder}. + * The first is to invoke the method on this interface directly. + * The second is to use {@link Temporal#plus(TemporalAdder)}: + *

    + *   // these two lines are equivalent, but the second approach is recommended
    + *   dateTime = adder.addTo(dateTime);
    + *   dateTime = dateTime.plus(adder);
    + * 
    + * It is recommended to use the second approach, {@code plus(TemporalAdder)}, + * as it is a lot clearer to read in code. + *

    + * The {@link Period} and {@link Duration} classes implement this interface. + * Adders may also be defined by applications. + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalAdder { + + /** + * Adds to the specified temporal object. + *

    + * This adds to the specified temporal object using the logic + * encapsulated in the implementing class. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#plus(TemporalAdder)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = adder.addTo(dateTime);
    +     *   dateTime = dateTime.plus(adder);
    +     * 
    + * It is recommended to use the second approach, {@code plus(TemporalAdder)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * The implementation must take the input object and add to it. + * The implementation defines the logic of the addition and is responsible for + * documenting that logic. It may use any method on {@code Temporal} to + * query the temporal object and perform the addition. + * The returned object must have the same observable type as the input object + *

    + * The input object must not be altered. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable temporal objects. + *

    + * The input temporal object may be in a calendar system other than ISO. + * Implementations may choose to document compatibility with other calendar systems, + * or reject non-ISO temporal objects by {@link Queries#chrono() querying the chronology}. + *

    + * This method may be called from multiple threads in parallel. + * It must be thread-safe when invoked. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same observable type with the addition made, not null + * @throws DateTimeException if unable to add + * @throws ArithmeticException if numeric overflow occurs + */ + Temporal addTo(Temporal temporal); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java b/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java new file mode 100644 index 00000000000..4a6f03d2875 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; + +/** + * Strategy for adjusting a temporal object. + *

    + * Adjusters are a key tool for modifying temporal objects. + * They exist to externalize the process of adjustment, permitting different + * approaches, as per the strategy design pattern. + * Examples might be an adjuster that sets the date avoiding weekends, or one that + * sets the date to the last day of the month. + *

    + * There are two equivalent ways of using a {@code TemporalAdjuster}. + * The first is to invoke the method on this interface directly. + * The second is to use {@link Temporal#with(TemporalAdjuster)}: + *

    + *   // these two lines are equivalent, but the second approach is recommended
    + *   temporal = thisAdjuster.adjustInto(temporal);
    + *   temporal = temporal.with(thisAdjuster);
    + * 
    + * It is recommended to use the second approach, {@code with(TemporalAdjuster)}, + * as it is a lot clearer to read in code. + *

    + * See {@link Adjusters} for a standard set of adjusters, including finding the + * last day of the month. + * Adjusters may also be defined by applications. + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalAdjuster { + + /** + * Adjusts the specified temporal object. + *

    + * This adjusts the specified temporal object using the logic + * encapsulated in the implementing class. + * Examples might be an adjuster that sets the date avoiding weekends, or one that + * sets the date to the last day of the month. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisAdjuster.adjustInto(temporal);
    +     *   temporal = temporal.with(thisAdjuster);
    +     * 
    + * It is recommended to use the second approach, {@code with(TemporalAdjuster)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * The implementation must take the input object and adjust it. + * The implementation defines the logic of the adjustment and is responsible for + * documenting that logic. It may use any method on {@code Temporal} to + * query the temporal object and perform the adjustment. + * The returned object must have the same observable type as the input object + *

    + * The input object must not be altered. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable temporal objects. + *

    + * The input temporal object may be in a calendar system other than ISO. + * Implementations may choose to document compatibility with other calendar systems, + * or reject non-ISO temporal objects by {@link Queries#chrono() querying the chronology}. + *

    + * This method may be called from multiple threads in parallel. + * It must be thread-safe when invoked. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same observable type with the adjustment made, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + Temporal adjustInto(Temporal temporal); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalField.java b/jdk/src/share/classes/java/time/temporal/TemporalField.java new file mode 100644 index 00000000000..187d9e9b049 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java @@ -0,0 +1,305 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.format.DateTimeBuilder; +import java.util.Comparator; + +/** + * A field of date-time, such as month-of-year or hour-of-minute. + *

    + * Date and time is expressed using fields which partition the time-line into something + * meaningful for humans. Implementations of this interface represent those fields. + *

    + * The most commonly used units are defined in {@link ChronoField}. + * Further fields are supplied in {@link ISOFields}, {@link WeekFields} and {@link JulianFields}. + * Fields can also be written by application code by implementing this interface. + *

    + * The field works using double dispatch. Client code calls methods on a date-time like + * {@code LocalDateTime} which check if the field is a {@code ChronoField}. + * If it is, then the date-time must handle it. + * Otherwise, the method call is re-dispatched to the matching method in this interface. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * It is recommended to use an enum where possible. + * + * @since 1.8 + */ +public interface TemporalField extends Comparator { + + /** + * Gets a descriptive name for the field. + *

    + * The should be of the format 'BaseOfRange', such as 'MonthOfYear', + * unless the field has a range of {@code FOREVER}, when only + * the base unit is mentioned, such as 'Year' or 'Era'. + * + * @return the name, not null + */ + String getName(); + + /** + * Gets the unit that the field is measured in. + *

    + * The unit of the field is the period that varies within the range. + * For example, in the field 'MonthOfYear', the unit is 'Months'. + * See also {@link #getRangeUnit()}. + * + * @return the period unit defining the base unit of the field, not null + */ + TemporalUnit getBaseUnit(); + + /** + * Gets the range that the field is bound by. + *

    + * The range of the field is the period that the field varies within. + * For example, in the field 'MonthOfYear', the range is 'Years'. + * See also {@link #getBaseUnit()}. + *

    + * The range is never null. For example, the 'Year' field is shorthand for + * 'YearOfForever'. It therefore has a unit of 'Years' and a range of 'Forever'. + * + * @return the period unit defining the range of the field, not null + */ + TemporalUnit getRangeUnit(); + + //----------------------------------------------------------------------- + /** + * Compares the value of this field in two temporal objects. + *

    + * All fields implement {@link Comparator} on {@link TemporalAccessor}. + * This allows a list of date-times to be compared using the value of a field. + * For example, you could sort a list of arbitrary temporal objects by the value of + * the month-of-year field - {@code Collections.sort(list, MONTH_OF_YEAR)} + *

    + * The default implementation must behave equivalent to this code: + *

    +     *  return Long.compare(temporal1.getLong(this), temporal2.getLong(this));
    +     * 
    + * + * @param temporal1 the first temporal object to compare, not null + * @param temporal2 the second temporal object to compare, not null + * @throws DateTimeException if unable to obtain the value for this field + */ + public default int compare(TemporalAccessor temporal1, TemporalAccessor temporal2) { + return Long.compare(temporal1.getLong(this), temporal2.getLong(this)); + } + + /** + * Gets the range of valid values for the field. + *

    + * All fields can be expressed as a {@code long} integer. + * This method returns an object that describes the valid range for that value. + * This method is generally only applicable to the ISO-8601 calendar system. + *

    + * Note that the result only describes the minimum and maximum valid values + * and it is important not to read too much into them. For example, there + * could be values within the range that are invalid for the field. + * + * @return the range of valid values for the field, not null + */ + ValueRange range(); + + //----------------------------------------------------------------------- + /** + * Checks if this field is supported by the temporal object. + *

    + * This determines whether the temporal accessor supports this field. + * If this returns false, the the temporal cannot be queried for this field. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link TemporalAccessor#isSupported(TemporalField)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisField.doIsSupported(temporal);
    +     *   temporal = temporal.isSupported(thisField);
    +     * 
    + * It is recommended to use the second approach, {@code isSupported(TemporalField)}, + * as it is a lot clearer to read in code. + *

    + * Implementations should determine whether they are supported using the fields + * available in {@link ChronoField}. + * + * @param temporal the temporal object to query, not null + * @return true if the date-time can be queried for this field, false if not + */ + boolean doIsSupported(TemporalAccessor temporal); + + /** + * Get the range of valid values for this field using the temporal object to + * refine the result. + *

    + * This uses the temporal object to find the range of valid values for the field. + * This is similar to {@link #range()}, however this method refines the result + * using the temporal. For example, if the field is {@code DAY_OF_MONTH} the + * {@code range} method is not accurate as there are four possible month lengths, + * 28, 29, 30 and 31 days. Using this method with a date allows the range to be + * accurate, returning just one of those four options. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link TemporalAccessor#range(TemporalField)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisField.doRange(temporal);
    +     *   temporal = temporal.range(thisField);
    +     * 
    + * It is recommended to use the second approach, {@code range(TemporalField)}, + * as it is a lot clearer to read in code. + *

    + * Implementations should perform any queries or calculations using the fields + * available in {@link ChronoField}. + * If the field is not supported a {@code DateTimeException} must be thrown. + * + * @param temporal the temporal object used to refine the result, not null + * @return the range of valid values for this field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + ValueRange doRange(TemporalAccessor temporal); + + /** + * Gets the value of this field from the specified temporal object. + *

    + * This queries the temporal object for the value of this field. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link TemporalAccessor#getLong(TemporalField)} + * (or {@link TemporalAccessor#get(TemporalField)}): + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisField.doGet(temporal);
    +     *   temporal = temporal.getLong(thisField);
    +     * 
    + * It is recommended to use the second approach, {@code getLong(TemporalField)}, + * as it is a lot clearer to read in code. + *

    + * Implementations should perform any queries or calculations using the fields + * available in {@link ChronoField}. + * If the field is not supported a {@code DateTimeException} must be thrown. + * + * @param temporal the temporal object to query, not null + * @return the value of this field, not null + * @throws DateTimeException if a value for the field cannot be obtained + */ + long doGet(TemporalAccessor temporal); + + /** + * Returns a copy of the specified temporal object with the value of this field set. + *

    + * This returns a new temporal object based on the specified one with the value for + * this field changed. For example, on a {@code LocalDate}, this could be used to + * set the year, month or day-of-month. + * The returned object has the same observable type as the specified object. + *

    + * In some cases, changing a field is not fully defined. For example, if the target object is + * a date representing the 31st January, then changing the month to February would be unclear. + * In cases like this, the implementation is responsible for resolving the result. + * Typically it will choose the previous valid date, which would be the last valid + * day of February in this example. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#with(TemporalField, long)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisField.doWith(temporal);
    +     *   temporal = temporal.with(thisField);
    +     * 
    + * It is recommended to use the second approach, {@code with(TemporalField)}, + * as it is a lot clearer to read in code. + *

    + * Implementations should perform any queries or calculations using the fields + * available in {@link ChronoField}. + * If the field is not supported a {@code DateTimeException} must be thrown. + *

    + * Implementations must not alter the specified temporal object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + * + * @param the type of the Temporal object + * @param temporal the temporal object to adjust, not null + * @param newValue the new value of the field + * @return the adjusted temporal object, not null + * @throws DateTimeException if the field cannot be set + */ + R doWith(R temporal, long newValue); + + /** + * Resolves the date/time information in the builder + *

    + * This method is invoked during the resolve of the builder. + * Implementations should combine the associated field with others to form + * objects like {@code LocalDate}, {@code LocalTime} and {@code LocalDateTime} + * + * @param builder the builder to resolve, not null + * @param value the value of the associated field + * @return true if builder has been changed, false otherwise + * @throws DateTimeException if unable to resolve + */ + boolean resolve(DateTimeBuilder builder, long value); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalQuery.java b/jdk/src/share/classes/java/time/temporal/TemporalQuery.java new file mode 100644 index 00000000000..a31964567b4 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalQuery.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; + +/** + * Strategy for querying a temporal object. + *

    + * Queries are a key tool for extracting information from temporal objects. + * They exist to externalize the process of querying, permitting different + * approaches, as per the strategy design pattern. + * Examples might be a query that checks if the date is the day before February 29th + * in a leap year, or calculates the number of days to your next birthday. + *

    + * The {@link TemporalField} interface provides another mechanism for querying + * temporal objects. That interface is limited to returning a {@code long}. + * By contrast, queries can return any type. + *

    + * There are two equivalent ways of using a {@code TemporalQuery}. + * The first is to invoke the method on this interface directly. + * The second is to use {@link TemporalAccessor#query(TemporalQuery)}: + *

    + *   // these two lines are equivalent, but the second approach is recommended
    + *   temporal = thisQuery.queryFrom(temporal);
    + *   temporal = temporal.query(thisQuery);
    + * 
    + * It is recommended to use the second approach, {@code query(TemporalQuery)}, + * as it is a lot clearer to read in code. + *

    + * The most common implementations are method references, such as + * {@code LocalDate::from} and {@code ZoneId::from}. + * Further implementations are on {@link Queries}. + * Queries may also be defined by applications. + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalQuery { + + /** + * Queries the specified temporal object. + *

    + * This queries the specified temporal object to return an object using the logic + * encapsulated in the implementing class. + * Examples might be a query that checks if the date is the day before February 29th + * in a leap year, or calculates the number of days to your next birthday. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link TemporalAccessor#query(TemporalQuery)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisQuery.queryFrom(temporal);
    +     *   temporal = temporal.query(thisQuery);
    +     * 
    + * It is recommended to use the second approach, {@code query(TemporalQuery)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * The implementation must take the input object and query it. + * The implementation defines the logic of the query and is responsible for + * documenting that logic. + * It may use any method on {@code TemporalAccessor} to determine the result. + * The input object must not be altered. + *

    + * The input temporal object may be in a calendar system other than ISO. + * Implementations may choose to document compatibility with other calendar systems, + * or reject non-ISO temporal objects by {@link Queries#chrono() querying the chronology}. + *

    + * This method may be called from multiple threads in parallel. + * It must be thread-safe when invoked. + * + * @param temporal the temporal object to query, not null + * @return the queried value, may return null to indicate not found + * @throws DateTimeException if unable to query + * @throws ArithmeticException if numeric overflow occurs + */ + R queryFrom(TemporalAccessor temporal); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java b/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java new file mode 100644 index 00000000000..4da8f30bea4 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Period; + +/** + * Strategy for subtracting from a temporal object. + *

    + * Subtractors are a key tool for modifying temporal objects. + * They exist to externalize the process of subtraction, permitting different + * approaches, as per the strategy design pattern. + *

    + * There are two equivalent ways of using a {@code TemporalSubtractor}. + * The first is to invoke the method on this interface directly. + * The second is to use {@link Temporal#minus(TemporalSubtractor)}: + *

    + *   // these two lines are equivalent, but the second approach is recommended
    + *   dateTime = subtractor.subtractFrom(dateTime);
    + *   dateTime = dateTime.minus(subtractor);
    + * 
    + * It is recommended to use the second approach, {@code minus(TemporalSubtractor)}, + * as it is a lot clearer to read in code. + *

    + * The {@link Period} and {@link Duration} classes implement this interface. + * Subtractors may also be defined by applications. + * + *

    Specification for implementors

    + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalSubtractor { + + /** + * Subtracts this object from the specified temporal object. + *

    + * This adds to the specified temporal object using the logic + * encapsulated in the implementing class. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#minus(TemporalSubtractor)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = subtractor.subtractFrom(dateTime);
    +     *   dateTime = dateTime.minus(subtractor);
    +     * 
    + * It is recommended to use the second approach, {@code minus(TemporalSubtractor)}, + * as it is a lot clearer to read in code. + * + *

    Specification for implementors

    + * The implementation must take the input object and subtract from it. + * The implementation defines the logic of the subtraction and is responsible for + * documenting that logic. It may use any method on {@code Temporal} to + * query the temporal object and perform the subtraction. + * The returned object must have the same observable type as the input object + *

    + * The input object must not be altered. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable temporal objects. + *

    + * The input temporal object may be in a calendar system other than ISO. + * Implementations may choose to document compatibility with other calendar systems, + * or reject non-ISO temporal objects by {@link Queries#chrono() querying the chronology}. + *

    + * This method may be called from multiple threads in parallel. + * It must be thread-safe when invoked. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same observable type with the subtraction made, not null + * @throws DateTimeException if unable to subtract + * @throws ArithmeticException if numeric overflow occurs + */ + Temporal subtractFrom(Temporal temporal); + +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java new file mode 100644 index 00000000000..7c8a32b4a3d --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* + * 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 java.time.temporal; + +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Period; + +/** + * A unit of date-time, such as Days or Hours. + *

    + * Measurement of time is built on units, such as years, months, days, hours, minutes and seconds. + * Implementations of this interface represent those units. + *

    + * An instance of this interface represents the unit itself, rather than an amount of the unit. + * See {@link Period} for a class that represents an amount in terms of the common units. + *

    + * The most commonly used units are defined in {@link ChronoUnit}. + * Further units are supplied in {@link ISOFields}. + * Units can also be written by application code by implementing this interface. + *

    + * The unit works using double dispatch. Client code calls methods on a date-time like + * {@code LocalDateTime} which check if the unit is a {@code ChronoUnit}. + * If it is, then the date-time must handle it. + * Otherwise, the method call is re-dispatched to the matching method in this interface. + * + *

    Specification for implementors

    + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * It is recommended to use an enum where possible. + * + * @since 1.8 + */ +public interface TemporalUnit { + + /** + * Gets a descriptive name for the unit. + *

    + * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'. + * + * @return the name, not null + */ + String getName(); + + /** + * Gets the duration of this unit, which may be an estimate. + *

    + * All units return a duration measured in standard nanoseconds from this method. + * For example, an hour has a duration of {@code 60 * 60 * 1,000,000,000ns}. + *

    + * Some units may return an accurate duration while others return an estimate. + * For example, days have an estimated duration due to the possibility of + * daylight saving time changes. + * To determine if the duration is an estimate, use {@link #isDurationEstimated()}. + * + * @return the duration of this unit, which may be an estimate, not null + */ + Duration getDuration(); + + /** + * Checks if the duration of the unit is an estimate. + *

    + * All units have a duration, however the duration is not always accurate. + * For example, days have an estimated duration due to the possibility of + * daylight saving time changes. + * This method returns true if the duration is an estimate and false if it is + * accurate. Note that accurate/estimated ignores leap seconds. + * + * @return true if the duration is estimated, false if accurate + */ + boolean isDurationEstimated(); + + //----------------------------------------------------------------------- + /** + * Checks if this unit is supported by the specified temporal object. + *

    + * This checks that the implementing date-time can add/subtract this unit. + * This can be used to avoid throwing an exception. + *

    + * This default implementation derives the value using + * {@link Temporal#plus(long, TemporalUnit)}. + * + * @param temporal the temporal object to check, not null + * @return true if the unit is supported + */ + public default boolean isSupported(Temporal temporal) { + try { + temporal.plus(1, this); + return true; + } catch (RuntimeException ex) { + try { + temporal.plus(-1, this); + return true; + } catch (RuntimeException ex2) { + return false; + } + } + } + + /** + * Returns a copy of the specified temporal object with the specified period added. + *

    + * The period added is a multiple of this unit. For example, this method + * could be used to add "3 days" to a date by calling this method on the + * instance representing "days", passing the date and the period "3". + * The period to be added may be negative, which is equivalent to subtraction. + *

    + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#plus(long, TemporalUnit)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisUnit.doPlus(temporal);
    +     *   temporal = temporal.plus(thisUnit);
    +     * 
    + * It is recommended to use the second approach, {@code plus(TemporalUnit)}, + * as it is a lot clearer to read in code. + *

    + * Implementations should perform any queries or calculations using the units + * available in {@link ChronoUnit} or the fields available in {@link ChronoField}. + * If the field is not supported a {@code DateTimeException} must be thrown. + *

    + * Implementations must not alter the specified temporal object. + * Instead, an adjusted copy of the original must be returned. + * This provides equivalent, safe behavior for immutable and mutable implementations. + * + * @param the type of the Temporal object + * @param dateTime the temporal object to adjust, not null + * @param periodToAdd the period of this unit to add, positive or negative + * @return the adjusted temporal object, not null + * @throws DateTimeException if the period cannot be added + */ + R doPlus(R dateTime, long periodToAdd); + + //----------------------------------------------------------------------- + /** + * Calculates the period in terms of this unit between two temporal objects of the same type. + *

    + * The period will be positive if the second date-time is after the first, and + * negative if the second date-time is before the first. + * Call {@link SimplePeriod#abs() abs()} on the result to ensure that the result + * is always positive. + *

    + * The result can be queried for the {@link SimplePeriod#getAmount() amount}, the + * {@link SimplePeriod#getUnit() unit} and used directly in addition/subtraction: + *

    +     *  date = date.minus(MONTHS.between(start, end));
    +     * 
    + * + * @param the type of the Temporal object; the two date-times must be of the same type + * @param dateTime1 the base temporal object, not null + * @param dateTime2 the other temporal object, not null + * @return the period between datetime1 and datetime2 in terms of this unit; + * positive if datetime2 is later than datetime1, not null + */ + SimplePeriod between(R dateTime1, R dateTime2); + + //----------------------------------------------------------------------- + /** + * Outputs this unit as a {@code String} using the name. + * + * @return the name of this unit, not null + */ + @Override + String toString(); + +} diff --git a/jdk/src/share/classes/java/time/temporal/ValueRange.java b/jdk/src/share/classes/java/time/temporal/ValueRange.java new file mode 100644 index 00000000000..cd47f256d4d --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/ValueRange.java @@ -0,0 +1,396 @@ +/* + * 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. + */ + +/* + * 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) 2011-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 java.time.temporal; + +import java.io.Serializable; +import java.time.DateTimeException; + +/** + * The range of valid values for a date-time field. + *

    + * All {@link TemporalField} instances have a valid range of values. + * For example, the ISO day-of-month runs from 1 to somewhere between 28 and 31. + * This class captures that valid range. + *

    + * It is important to be aware of the limitations of this class. + * Only the minimum and maximum values are provided. + * It is possible for there to be invalid values within the outer range. + * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus + * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid. + *

    + * Instances of this class are not tied to a specific field. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ValueRange implements Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -7317881728594519368L; + + /** + * The smallest minimum value. + */ + private final long minSmallest; + /** + * The largest minimum value. + */ + private final long minLargest; + /** + * The smallest maximum value. + */ + private final long maxSmallest; + /** + * The largest maximum value. + */ + private final long maxLargest; + + /** + * Obtains a fixed value range. + *

    + * This factory obtains a range where the minimum and maximum values are fixed. + * For example, the ISO month-of-year always runs from 1 to 12. + * + * @param min the minimum value + * @param max the maximum value + * @return the ValueRange for min, max, not null + * @throws IllegalArgumentException if the minimum is greater than the maximum + */ + public static ValueRange of(long min, long max) { + if (min > max) { + throw new IllegalArgumentException("Minimum value must be less than maximum value"); + } + return new ValueRange(min, min, max, max); + } + + /** + * Obtains a variable value range. + *

    + * This factory obtains a range where the minimum value is fixed and the maximum value may vary. + * For example, the ISO day-of-month always starts at 1, but ends between 28 and 31. + * + * @param min the minimum value + * @param maxSmallest the smallest maximum value + * @param maxLargest the largest maximum value + * @return the ValueRange for min, smallest max, largest max, not null + * @throws IllegalArgumentException if + * the minimum is greater than the smallest maximum, + * or the smallest maximum is greater than the largest maximum + */ + public static ValueRange of(long min, long maxSmallest, long maxLargest) { + return of(min, min, maxSmallest, maxLargest); + } + + /** + * Obtains a fully variable value range. + *

    + * This factory obtains a range where both the minimum and maximum value may vary. + * + * @param minSmallest the smallest minimum value + * @param minLargest the largest minimum value + * @param maxSmallest the smallest maximum value + * @param maxLargest the largest maximum value + * @return the ValueRange for smallest min, largest min, smallest max, largest max, not null + * @throws IllegalArgumentException if + * the smallest minimum is greater than the smallest maximum, + * or the smallest maximum is greater than the largest maximum + * or the largest minimum is greater than the largest maximum + */ + public static ValueRange of(long minSmallest, long minLargest, long maxSmallest, long maxLargest) { + if (minSmallest > minLargest) { + throw new IllegalArgumentException("Smallest minimum value must be less than largest minimum value"); + } + if (maxSmallest > maxLargest) { + throw new IllegalArgumentException("Smallest maximum value must be less than largest maximum value"); + } + if (minLargest > maxLargest) { + throw new IllegalArgumentException("Minimum value must be less than maximum value"); + } + return new ValueRange(minSmallest, minLargest, maxSmallest, maxLargest); + } + + /** + * Restrictive constructor. + * + * @param minSmallest the smallest minimum value + * @param minLargest the largest minimum value + * @param maxSmallest the smallest minimum value + * @param maxLargest the largest minimum value + */ + private ValueRange(long minSmallest, long minLargest, long maxSmallest, long maxLargest) { + this.minSmallest = minSmallest; + this.minLargest = minLargest; + this.maxSmallest = maxSmallest; + this.maxLargest = maxLargest; + } + + //----------------------------------------------------------------------- + /** + * Is the value range fixed and fully known. + *

    + * For example, the ISO day-of-month runs from 1 to between 28 and 31. + * Since there is uncertainty about the maximum value, the range is not fixed. + * However, for the month of January, the range is always 1 to 31, thus it is fixed. + * + * @return true if the set of values is fixed + */ + public boolean isFixed() { + return minSmallest == minLargest && maxSmallest == maxLargest; + } + + //----------------------------------------------------------------------- + /** + * Gets the minimum value that the field can take. + *

    + * For example, the ISO day-of-month always starts at 1. + * The minimum is therefore 1. + * + * @return the minimum value for this field + */ + public long getMinimum() { + return minSmallest; + } + + /** + * Gets the largest possible minimum value that the field can take. + *

    + * For example, the ISO day-of-month always starts at 1. + * The largest minimum is therefore 1. + * + * @return the largest possible minimum value for this field + */ + public long getLargestMinimum() { + return minLargest; + } + + /** + * Gets the smallest possible maximum value that the field can take. + *

    + * For example, the ISO day-of-month runs to between 28 and 31 days. + * The smallest maximum is therefore 28. + * + * @return the smallest possible maximum value for this field + */ + public long getSmallestMaximum() { + return maxSmallest; + } + + /** + * Gets the maximum value that the field can take. + *

    + * For example, the ISO day-of-month runs to between 28 and 31 days. + * The maximum is therefore 31. + * + * @return the maximum value for this field + */ + public long getMaximum() { + return maxLargest; + } + + //----------------------------------------------------------------------- + /** + * Checks if all values in the range fit in an {@code int}. + *

    + * This checks that all valid values are within the bounds of an {@code int}. + *

    + * For example, the ISO month-of-year has values from 1 to 12, which fits in an {@code int}. + * By comparison, ISO nano-of-day runs from 1 to 86,400,000,000,000 which does not fit in an {@code int}. + *

    + * This implementation uses {@link #getMinimum()} and {@link #getMaximum()}. + * + * @return true if a valid value always fits in an {@code int} + */ + public boolean isIntValue() { + return getMinimum() >= Integer.MIN_VALUE && getMaximum() <= Integer.MAX_VALUE; + } + + /** + * Checks if the value is within the valid range. + *

    + * This checks that the value is within the stored range of values. + * + * @param value the value to check + * @return true if the value is valid + */ + public boolean isValidValue(long value) { + return (value >= getMinimum() && value <= getMaximum()); + } + + /** + * Checks if the value is within the valid range and that all values + * in the range fit in an {@code int}. + *

    + * This method combines {@link #isIntValue()} and {@link #isValidValue(long)}. + * + * @param value the value to check + * @return true if the value is valid and fits in an {@code int} + */ + public boolean isValidIntValue(long value) { + return isIntValue() && isValidValue(value); + } + + /** + * Checks that the specified value is valid. + *

    + * This validates that the value is within the valid range of values. + * The field is only used to improve the error message. + * + * @param value the value to check + * @param field the field being checked, may be null + * @return the value that was passed in + * @see #isValidValue(long) + */ + public long checkValidValue(long value, TemporalField field) { + if (isValidValue(value) == false) { + if (field != null) { + throw new DateTimeException("Invalid value for " + field.getName() + " (valid values " + this + "): " + value); + } else { + throw new DateTimeException("Invalid value (valid values " + this + "): " + value); + } + } + return value; + } + + /** + * Checks that the specified value is valid and fits in an {@code int}. + *

    + * This validates that the value is within the valid range of values and that + * all valid values are within the bounds of an {@code int}. + * The field is only used to improve the error message. + * + * @param value the value to check + * @param field the field being checked, may be null + * @return the value that was passed in + * @see #isValidIntValue(long) + */ + public int checkValidIntValue(long value, TemporalField field) { + if (isValidIntValue(value) == false) { + throw new DateTimeException("Invalid int value for " + field.getName() + ": " + value); + } + return (int) value; + } + + //----------------------------------------------------------------------- + /** + * Checks if this range is equal to another range. + *

    + * The comparison is based on the four values, minimum, largest minimum, + * smallest maximum and maximum. + * Only objects of type {@code ValueRange} are compared, other types return false. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other range + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof ValueRange) { + ValueRange other = (ValueRange) obj; + return minSmallest == other.minSmallest && minLargest == other.minLargest && + maxSmallest == other.maxSmallest && maxLargest == other.maxLargest; + } + return false; + } + + /** + * A hash code for this range. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + long hash = minSmallest + minLargest << 16 + minLargest >> 48 + maxSmallest << 32 + + maxSmallest >> 32 + maxLargest << 48 + maxLargest >> 16; + return (int) (hash ^ (hash >>> 32)); + } + + //----------------------------------------------------------------------- + /** + * Outputs this range as a {@code String}. + *

    + * The format will be '{min}/{largestMin} - {smallestMax}/{max}', + * where the largestMin or smallestMax sections may be omitted, together + * with associated slash, if they are the same as the min or max. + * + * @return a string representation of this range, not null + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(minSmallest); + if (minSmallest != minLargest) { + buf.append('/').append(minLargest); + } + buf.append(" - ").append(maxSmallest); + if (maxSmallest != maxLargest) { + buf.append('/').append(maxLargest); + } + return buf.toString(); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/WeekFields.java b/jdk/src/share/classes/java/time/temporal/WeekFields.java new file mode 100644 index 00000000000..364aa91798e --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java @@ -0,0 +1,663 @@ +/* + * 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. + */ + +/* + * 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) 2011-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 java.time.temporal; + +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.time.DayOfWeek; +import java.time.format.DateTimeBuilder; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Localized definitions of the day-of-week, week-of-month and week-of-year fields. + *

    + * A standard week is seven days long, but cultures have different definitions for some + * other aspects of a week. This class represents the definition of the week, for the + * purpose of providing {@link TemporalField} instances. + *

    + * WeekFields provides three fields, + * {@link #dayOfWeek()}, {@link #weekOfMonth()}, and {@link #weekOfYear()} + * that provide access to the values from any {@linkplain Temporal temporal object}. + *

    + * The computations for day-of-week, week-of-month, and week-of-year are based + * on the {@linkplain ChronoField#YEAR proleptic-year}, + * {@linkplain ChronoField#MONTH_OF_YEAR month-of-year}, + * {@linkplain ChronoField#DAY_OF_MONTH day-of-month}, and + * {@linkplain ChronoField#DAY_OF_WEEK ISO day-of-week} which are based on the + * {@linkplain ChronoField#EPOCH_DAY epoch-day} and the chronology. + * The values may not be aligned with the {@linkplain ChronoField#YEAR_OF_ERA year-of-Era} + * depending on the Chronology. + *

    A week is defined by: + *

      + *
    • The first day-of-week. + * For example, the ISO-8601 standard considers Monday to be the first day-of-week. + *
    • The minimal number of days in the first week. + * For example, the ISO-08601 standard counts the first week as needing at least 4 days. + *

    + * Together these two values allow a year or month to be divided into weeks. + *

    + *

    Week of Month

    + * One field is used: week-of-month. + * The calculation ensures that weeks never overlap a month boundary. + * The month is divided into periods where each period starts on the defined first day-of-week. + * The earliest period is referred to as week 0 if it has less than the minimal number of days + * and week 1 if it has at least the minimal number of days. + *

    + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of WeekFields
    DateDay-of-weekFirst day: Monday
    Minimal days: 4
    First day: Monday
    Minimal days: 5
    2008-12-31WednesdayWeek 5 of December 2008Week 5 of December 2008
    2009-01-01ThursdayWeek 1 of January 2009Week 0 of January 2009
    2009-01-04SundayWeek 1 of January 2009Week 0 of January 2009
    2009-01-05MondayWeek 2 of January 2009Week 1 of January 2009
    + *

    + *

    Week of Year

    + * One field is used: week-of-year. + * The calculation ensures that weeks never overlap a year boundary. + * The year is divided into periods where each period starts on the defined first day-of-week. + * The earliest period is referred to as week 0 if it has less than the minimal number of days + * and week 1 if it has at least the minimal number of days. + *

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class WeekFields implements Serializable { + // implementation notes + // querying week-of-month or week-of-year should return the week value bound within the month/year + // however, setting the week value should be lenient (use plus/minus weeks) + // allow week-of-month outer range [0 to 5] + // allow week-of-year outer range [0 to 53] + // this is because callers shouldn't be expected to know the details of validity + + /** + * The cache of rules by firstDayOfWeek plus minimalDays. + * Initialized first to be available for definition of ISO, etc. + */ + private static final ConcurrentMap CACHE = new ConcurrentHashMap<>(4, 0.75f, 2); + + /** + * The ISO-8601 definition, where a week starts on Monday and the first week + * has a minimum of 4 days. + *

    + * The ISO-8601 standard defines a calendar system based on weeks. + * It uses the week-based-year and week-of-week-based-year concepts to split + * up the passage of days instead of the standard year/month/day. + *

    + * Note that the first week may start in the previous calendar year. + * Note also that the first few days of a calendar year may be in the + * week-based-year corresponding to the previous calendar year. + */ + public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4); + + /** + * The common definition of a week that starts on Sunday. + *

    + * Defined as starting on Sunday and with a minimum of 1 day in the month. + * This week definition is in use in the US and other European countries. + * + */ + public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1); + + /** + * Serialization version. + */ + private static final long serialVersionUID = -1177360819670808121L; + + /** + * The first day-of-week. + */ + private final DayOfWeek firstDayOfWeek; + /** + * The minimal number of days in the first week. + */ + private final int minimalDays; + + /** + * The field used to access the computed DayOfWeek. + */ + private transient final TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this); + + /** + * The field used to access the computed WeekOfMonth. + */ + private transient final TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this); + + /** + * The field used to access the computed WeekOfYear. + */ + private transient final TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this); + + /** + * Obtains an instance of {@code WeekFields} appropriate for a locale. + *

    + * This will look up appropriate values from the provider of localization data. + * + * @param locale the locale to use, not null + * @return the week-definition, not null + */ + public static WeekFields of(Locale locale) { + Objects.requireNonNull(locale, "locale"); + locale = new Locale(locale.getLanguage(), locale.getCountry()); // elminate variants + + // obtain these from GregorianCalendar for now + // TODO: consider getting them directly from the spi + GregorianCalendar gcal = new GregorianCalendar(locale); + int calDow = gcal.getFirstDayOfWeek(); + DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1); + int minDays = gcal.getMinimalDaysInFirstWeek(); + return WeekFields.of(dow, minDays); + } + + /** + * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days. + *

    + * The first day-of-week defines the ISO {@code DayOfWeek} that is day 1 of the week. + * The minimal number of days in the first week defines how many days must be present + * in a month or year, starting from the first day-of-week, before the week is counted + * as the first week. A value of 1 will count the first day of the month or year as part + * of the first week, whereas a value of 7 will require the whole seven days to be in + * the new month or year. + *

    + * WeekFields instances are singletons; for each unique combination + * of {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} the + * the same instance will be returned. + * + * @param firstDayOfWeek the first day of the week, not null + * @param minimalDaysInFirstWeek the minimal number of days in the first week, from 1 to 7 + * @return the week-definition, not null + * @throws IllegalArgumentException if the minimal days value is less than one + * or greater than 7 + */ + public static WeekFields of(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) { + String key = firstDayOfWeek.toString() + minimalDaysInFirstWeek; + WeekFields rules = CACHE.get(key); + if (rules == null) { + rules = new WeekFields(firstDayOfWeek, minimalDaysInFirstWeek); + CACHE.putIfAbsent(key, rules); + rules = CACHE.get(key); + } + return rules; + } + + //----------------------------------------------------------------------- + /** + * Creates an instance of the definition. + * + * @param firstDayOfWeek the first day of the week, not null + * @param minimalDaysInFirstWeek the minimal number of days in the first week, from 1 to 7 + * @throws IllegalArgumentException if the minimal days value is invalid + */ + private WeekFields(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) { + Objects.requireNonNull(firstDayOfWeek, "firstDayOfWeek"); + if (minimalDaysInFirstWeek < 1 || minimalDaysInFirstWeek > 7) { + throw new IllegalArgumentException("Minimal number of days is invalid"); + } + this.firstDayOfWeek = firstDayOfWeek; + this.minimalDays = minimalDaysInFirstWeek; + } + + //----------------------------------------------------------------------- + /** + * Return the singleton WeekFields associated with the + * {@code firstDayOfWeek} and {@code minimalDays}. + * @return the singleton WeekFields for the firstDayOfWeek and minimalDays. + * @throws InvalidObjectException if the serialized object has invalid + * values for firstDayOfWeek or minimalDays. + */ + private Object readResolve() throws InvalidObjectException { + try { + return WeekFields.of(firstDayOfWeek, minimalDays); + } catch (IllegalArgumentException iae) { + throw new InvalidObjectException("Invalid serialized WeekFields: " + + iae.getMessage()); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the first day-of-week. + *

    + * The first day-of-week varies by culture. + * For example, the US uses Sunday, while France and the ISO-8601 standard use Monday. + * This method returns the first day using the standard {@code DayOfWeek} enum. + * + * @return the first day-of-week, not null + */ + public DayOfWeek getFirstDayOfWeek() { + return firstDayOfWeek; + } + + /** + * Gets the minimal number of days in the first week. + *

    + * The number of days considered to define the first week of a month or year + * varies by culture. + * For example, the ISO-8601 requires 4 days (more than half a week) to + * be present before counting the first week. + * + * @return the minimal number of days in the first week of a month or year, from 1 to 7 + */ + public int getMinimalDaysInFirstWeek() { + return minimalDays; + } + + //----------------------------------------------------------------------- + /** + * Returns a field to access the day of week, + * computed based on this WeekFields. + *

    + * The days of week are numbered from 1 to 7. + * Day number 1 is the {@link #getFirstDayOfWeek() first day-of-week}. + * + * @return the field for day-of-week using this week definition, not null + */ + public TemporalField dayOfWeek() { + return dayOfWeek; + } + + /** + * Returns a field to access the week of month, + * computed based on this WeekFields. + *

    + * This represents concept of the count of weeks within the month where weeks + * start on a fixed day-of-week, such as Monday. + * This field is typically used with {@link WeekFields#dayOfWeek()}. + *

    + * Week one (1) is the week starting on the {@link WeekFields#getFirstDayOfWeek} + * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month. + * Thus, week one may start up to {@code minDays} days before the start of the month. + * If the first week starts after the start of the month then the period before is week zero (0). + *

    + * For example:
    + * - if the 1st day of the month is a Monday, week one starts on the 1st and there is no week zero
    + * - if the 2nd day of the month is a Monday, week one starts on the 2nd and the 1st is in week zero
    + * - if the 4th day of the month is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero
    + * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one
    + *

    + * This field can be used with any calendar system. + * @return a TemporalField to access the WeekOfMonth, not null + */ + public TemporalField weekOfMonth() { + return weekOfMonth; + } + + /** + * Returns a field to access the week of year, + * computed based on this WeekFields. + *

    + * This represents concept of the count of weeks within the year where weeks + * start on a fixed day-of-week, such as Monday. + * This field is typically used with {@link WeekFields#dayOfWeek()}. + *

    + * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek} + * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month. + * Thus, week one may start up to {@code minDays} days before the start of the year. + * If the first week starts after the start of the year then the period before is week zero (0). + *

    + * For example:
    + * - if the 1st day of the year is a Monday, week one starts on the 1st and there is no week zero
    + * - if the 2nd day of the year is a Monday, week one starts on the 2nd and the 1st is in week zero
    + * - if the 4th day of the year is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero
    + * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one
    + *

    + * This field can be used with any calendar system. + * @return a TemporalField to access the WeekOfYear, not null + */ + public TemporalField weekOfYear() { + return weekOfYear; + } + + /** + * Checks if these rules are equal to the specified rules. + *

    + * The comparison is based on the entire state of the rules, which is + * the first day-of-week and minimal days. + * + * @param object the other rules to compare to, null returns false + * @return true if this is equal to the specified rules + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof WeekFields) { + return hashCode() == object.hashCode(); + } + return false; + } + + /** + * A hash code for these rules. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return firstDayOfWeek.ordinal() * 7 + minimalDays; + } + + //----------------------------------------------------------------------- + /** + * A string representation of this definition. + * + * @return the string representation, not null + */ + @Override + public String toString() { + return "WeekFields[" + firstDayOfWeek + ',' + minimalDays + ']'; + } + + //----------------------------------------------------------------------- + /** + * Field type that computes DayOfWeek, WeekOfMonth, and WeekOfYear + * based on a WeekFields. + * A separate Field instance is required for each different WeekFields; + * combination of start of week and minimum number of days. + * Constructors are provided to create fields for DayOfWeek, WeekOfMonth, + * and WeekOfYear. + */ + static class ComputedDayOfField implements TemporalField { + + /** + * Returns a field to access the day of week, + * computed based on a WeekFields. + *

    + * The WeekDefintion of the first day of the week is used with + * the ISO DAY_OF_WEEK field to compute week boundaries. + */ + static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) { + return new ComputedDayOfField("DayOfWeek", weekDef, + ChronoUnit.DAYS, ChronoUnit.WEEKS, DAY_OF_WEEK_RANGE); + } + + /** + * Returns a field to access the week of month, + * computed based on a WeekFields. + * @see WeekFields#weekOfMonth() + */ + static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) { + return new ComputedDayOfField("WeekOfMonth", weekDef, + ChronoUnit.WEEKS, ChronoUnit.MONTHS, WEEK_OF_MONTH_RANGE); + } + + /** + * Returns a field to access the week of year, + * computed based on a WeekFields. + * @see WeekFields#weekOfYear() + */ + static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) { + return new ComputedDayOfField("WeekOfYear", weekDef, + ChronoUnit.WEEKS, ChronoUnit.YEARS, WEEK_OF_YEAR_RANGE); + } + private final String name; + private final WeekFields weekDef; + private final TemporalUnit baseUnit; + private final TemporalUnit rangeUnit; + private final ValueRange range; + + private ComputedDayOfField(String name, WeekFields weekDef, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) { + this.name = name; + this.weekDef = weekDef; + this.baseUnit = baseUnit; + this.rangeUnit = rangeUnit; + this.range = range; + } + + private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7); + private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 5); + private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 53); + + @Override + public long doGet(TemporalAccessor temporal) { + // Offset the ISO DOW by the start of this week + int sow = weekDef.getFirstDayOfWeek().getValue(); + int isoDow = temporal.get(ChronoField.DAY_OF_WEEK); + int dow = Math.floorMod(isoDow - sow, 7) + 1; + + if (rangeUnit == ChronoUnit.WEEKS) { + return dow; + } else if (rangeUnit == ChronoUnit.MONTHS) { + int dom = temporal.get(ChronoField.DAY_OF_MONTH); + int offset = startOfWeekOffset(dom, dow); + return computeWeek(offset, dom); + } else if (rangeUnit == ChronoUnit.YEARS) { + int doy = temporal.get(ChronoField.DAY_OF_YEAR); + int offset = startOfWeekOffset(doy, dow); + return computeWeek(offset, doy); + } else { + throw new IllegalStateException("unreachable"); + } + } + + /** + * Returns an offset to align week start with a day of month or day of year. + * + * @param day the day; 1 through infinity + * @param dow the day of the week of that day; 1 through 7 + * @return an offset in days to align a day with the start of the first 'full' week + */ + private int startOfWeekOffset(int day, int dow) { + // offset of first day corresponding to the day of week in first 7 days (zero origin) + int weekStart = Math.floorMod(day - dow, 7); + int offset = -weekStart; + if (weekStart + 1 > weekDef.getMinimalDaysInFirstWeek()) { + // The previous week has the minimum days in the current month to be a 'week' + offset = 7 - weekStart; + } + return offset; + } + + /** + * Returns the week number computed from the reference day and reference dayOfWeek. + * + * @param offset the offset to align a date with the start of week + * from {@link #startOfWeekOffset}. + * @param day the day for which to compute the week number + * @return the week number where zero is used for a partial week and 1 for the first full week + */ + private int computeWeek(int offset, int day) { + return ((7 + offset + (day - 1)) / 7); + } + + @Override + public R doWith(R temporal, long newValue) { + // Check the new value and get the old value of the field + int newVal = range.checkValidIntValue(newValue, this); + int currentVal = temporal.get(this); + if (newVal == currentVal) { + return temporal; + } + // Compute the difference and add that using the base using of the field + int delta = newVal - currentVal; + return (R) temporal.plus(delta, baseUnit); + } + + @Override + public boolean resolve(DateTimeBuilder builder, long value) { + int newValue = range.checkValidIntValue(value, this); + // DOW and YEAR are necessary for all fields; Chrono defaults to ISO if not present + int sow = weekDef.getFirstDayOfWeek().getValue(); + int dow = builder.get(weekDef.dayOfWeek()); + int year = builder.get(ChronoField.YEAR); + Chrono chrono = Chrono.from(builder); + + // The WOM and WOY fields are the critical values + if (rangeUnit == ChronoUnit.MONTHS) { + // Process WOM value by combining with DOW and MONTH, YEAR + int month = builder.get(ChronoField.MONTH_OF_YEAR); + ChronoLocalDate cd = chrono.date(year, month, 1); + int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek())); + offset += dow - 1; // offset to desired day of week + offset += 7 * (newValue - 1); // offset by week number + ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS); + builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH)); + builder.removeFieldValue(this); + builder.removeFieldValue(weekDef.dayOfWeek()); + return true; + } else if (rangeUnit == ChronoUnit.YEARS) { + // Process WOY + ChronoLocalDate cd = chrono.date(year, 1, 1); + int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek())); + offset += dow - 1; // offset to desired day of week + offset += 7 * (newValue - 1); // offset by week number + ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS); + builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH)); + builder.addFieldValue(ChronoField.MONTH_OF_YEAR, result.get(ChronoField.MONTH_OF_YEAR)); + builder.removeFieldValue(this); + builder.removeFieldValue(weekDef.dayOfWeek()); + return true; + } else { + // ignore DOW of WEEK field; the value will be processed by WOM or WOY + int isoDow = Math.floorMod((sow - 1) + (dow - 1), 7) + 1; + builder.addFieldValue(ChronoField.DAY_OF_WEEK, isoDow); + // Not removed, the week-of-xxx fields need this value + return true; + } + } + + //----------------------------------------------------------------------- + @Override + public String getName() { + return name; + } + + @Override + public TemporalUnit getBaseUnit() { + return baseUnit; + } + + @Override + public TemporalUnit getRangeUnit() { + return rangeUnit; + } + + @Override + public ValueRange range() { + return range; + } + + //------------------------------------------------------------------------- + @Override + public int compare(TemporalAccessor temporal1, TemporalAccessor temporal2) { + return Long.compare(temporal1.getLong(this), temporal2.getLong(this)); + } + + //----------------------------------------------------------------------- + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + if (temporal.isSupported(ChronoField.DAY_OF_WEEK)) { + if (rangeUnit == ChronoUnit.WEEKS) { + return true; + } else if (rangeUnit == ChronoUnit.MONTHS) { + return temporal.isSupported(ChronoField.DAY_OF_MONTH); + } else if (rangeUnit == ChronoUnit.YEARS) { + return temporal.isSupported(ChronoField.DAY_OF_YEAR); + } + } + return false; + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + if (rangeUnit == ChronoUnit.WEEKS) { + return range; + } + + TemporalField field = null; + if (rangeUnit == ChronoUnit.MONTHS) { + field = ChronoField.DAY_OF_MONTH; + } else if (rangeUnit == ChronoUnit.YEARS) { + field = ChronoField.DAY_OF_YEAR; + } else { + throw new IllegalStateException("unreachable"); + } + + // Offset the ISO DOW by the start of this week + int sow = weekDef.getFirstDayOfWeek().getValue(); + int isoDow = temporal.get(ChronoField.DAY_OF_WEEK); + int dow = Math.floorMod(isoDow - sow, 7) + 1; + + int offset = startOfWeekOffset(temporal.get(field), dow); + ValueRange fieldRange = temporal.range(field); + return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()), + computeWeek(offset, (int) fieldRange.getMaximum())); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + return getName() + "[" + weekDef.toString() + "]"; + } + } +} diff --git a/jdk/src/share/classes/java/time/temporal/Year.java b/jdk/src/share/classes/java/time/temporal/Year.java new file mode 100644 index 00000000000..f54acf721f8 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/Year.java @@ -0,0 +1,996 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +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.ChronoUnit.YEARS; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.SignStyle; +import java.util.Objects; + +/** + * A year in the ISO-8601 calendar system, such as {@code 2007}. + *

    + * {@code Year} is an immutable date-time object that represents a year. + * Any field that can be derived from a year can be obtained. + *

    + * Note that years in the ISO chronology only align with years in the + * Gregorian-Julian system for modern years. Parts of Russia did not switch to the + * modern Gregorian/ISO rules until 1920. + * As such, historical years must be treated with caution. + *

    + * This class does not store or represent a month, day, time or time-zone. + * For example, the value "2007" can be stored in a {@code Year}. + *

    + * Years represented by this class follow the ISO-8601 standard and use + * the proleptic numbering system. Year 1 is preceded by year 0, then by year -1. + *

    + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * For most applications written today, the ISO-8601 rules are entirely suitable. + * However, any application that makes use of historical dates, and requires them + * to be accurate will find the ISO-8601 approach unsuitable. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class Year + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * The minimum supported year, '-999,999,999'. + */ + public static final int MIN_VALUE = -999_999_999; + /** + * The maximum supported year, '+999,999,999'. + */ + public static final int MAX_VALUE = 999_999_999; + + /** + * Serialization version. + */ + private static final long serialVersionUID = -23038383694477807L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .toFormatter(); + + /** + * The year being represented. + */ + private final int year; + + //----------------------------------------------------------------------- + /** + * Obtains the current year from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current year. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current year using the system clock and default time-zone, not null + */ + public static Year now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current year from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year. + * Specifying the time-zone avoids dependence on the default time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current year using the system clock, not null + */ + public static Year now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current year from the specified clock. + *

    + * This will query the specified clock to obtain the current year. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current year, not null + */ + public static Year now(Clock clock) { + final LocalDate now = LocalDate.now(clock); // called once + return Year.of(now.getYear()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Year}. + *

    + * This method accepts a year value from the proleptic ISO calendar system. + *

    + * The year 2AD/CE is represented by 2.
    + * The year 1AD/CE is represented by 1.
    + * The year 1BC/BCE is represented by 0.
    + * The year 2BC/BCE is represented by -1.
    + * + * @param isoYear the ISO proleptic year to represent, from {@code MIN_VALUE} to {@code MAX_VALUE} + * @return the year, not null + * @throws DateTimeException if the field is invalid + */ + public static Year of(int isoYear) { + YEAR.checkValidValue(isoYear); + return new Year(isoYear); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Year} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code Year}. + *

    + * The conversion extracts the {@link ChronoField#YEAR year} field. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code Year::from}. + * + * @param temporal the temporal object to convert, not null + * @return the year, not null + * @throws DateTimeException if unable to convert to a {@code Year} + */ + public static Year from(TemporalAccessor temporal) { + if (temporal instanceof Year) { + return (Year) temporal; + } + try { + if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) { + temporal = LocalDate.from(temporal); + } + return of(temporal.get(YEAR)); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain Year from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code Year} from a text string such as {@code 2007}. + *

    + * The string must represent a valid year. + * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol. + * + * @param text the text to parse such as "2007", not null + * @return the parsed year, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static Year parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code Year} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a year. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed year, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static Year parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, Year::from); + } + + //------------------------------------------------------------------------- + /** + * Checks if the year is a leap year, according to the ISO proleptic + * calendar system rules. + *

    + * This method applies the current rules for leap years across the whole time-line. + * In general, a year is a leap year if it is divisible by four without + * remainder. However, years divisible by 100, are not leap years, with + * the exception of years divisible by 400 which are. + *

    + * For example, 1904 is a leap year it is divisible by 4. + * 1900 was not a leap year as it is divisible by 100, however 2000 was a + * leap year as it is divisible by 400. + *

    + * The calculation is proleptic - applying the same rules into the far future and far past. + * This is historically inaccurate, but is correct for the ISO-8601 standard. + * + * @param year the year to check + * @return true if the year is leap, false otherwise + */ + public static boolean isLeap(long year) { + return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param year the year to represent + */ + private Year(int year) { + this.year = year; + } + + //----------------------------------------------------------------------- + /** + * Gets the year value. + *

    + * The year returned by this method is proleptic as per {@code get(YEAR)}. + * + * @return the year, {@code MIN_VALUE} to {@code MAX_VALUE} + */ + public int getValue() { + return year; + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this year can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * The supported fields are: + *

      + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this year, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == YEAR || field == YEAR_OF_ERA || field == ERA; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This year is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field == YEAR_OF_ERA) { + return (year <= 0 ? ValueRange.of(1, MAX_VALUE + 1) : ValueRange.of(1, MAX_VALUE)); + } + return Temporal.super.range(field); + } + + /** + * Gets the value of the specified field from this year as an {@code int}. + *

    + * This queries this year for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this year as a {@code long}. + *

    + * This queries this year for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case YEAR_OF_ERA: return (year < 1 ? 1 - year : year); + case YEAR: return year; + case ERA: return (year < 1 ? 0 : 1); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doGet(this); + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is a leap year, according to the ISO proleptic + * calendar system rules. + *

    + * This method applies the current rules for leap years across the whole time-line. + * In general, a year is a leap year if it is divisible by four without + * remainder. However, years divisible by 100, are not leap years, with + * the exception of years divisible by 400 which are. + *

    + * For example, 1904 is a leap year it is divisible by 4. + * 1900 was not a leap year as it is divisible by 100, however 2000 was a + * leap year as it is divisible by 400. + *

    + * The calculation is proleptic - applying the same rules into the far future and far past. + * This is historically inaccurate, but is correct for the ISO-8601 standard. + * + * @return true if the year is leap, false otherwise + */ + public boolean isLeap() { + return Year.isLeap(year); + } + + /** + * Checks if the month-day is valid for this year. + *

    + * This method checks whether this year and the input month and day form + * a valid date. + * + * @param monthDay the month-day to validate, null returns false + * @return true if the month and day are valid for this year + */ + public boolean isValidMonthDay(MonthDay monthDay) { + return monthDay != null && monthDay.isValidYear(year); + } + + /** + * Gets the length of this year in days. + * + * @return the length of this year in days, 365 or 366 + */ + public int length() { + return isLeap() ? 366 : 365; + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this year. + *

    + * This returns a new {@code Year}, based on this one, with the year adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return a {@code Year} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Year with(TemporalAdjuster adjuster) { + return (Year) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this year with the specified field set to a new value. + *

    + * This returns a new {@code Year}, based on this one, with the value + * for the specified field changed. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the adjustment is implemented here. + * The supported fields behave as follows: + *

      + *
    • {@code YEAR_OF_ERA} - + * Returns a {@code Year} with the specified year-of-era + * The era will be unchanged. + *
    • {@code YEAR} - + * Returns a {@code Year} with the specified year. + * This completely replaces the date and is equivalent to {@link #of(int)}. + *
    • {@code ERA} - + * Returns a {@code Year} with the specified era. + * The year-of-era will be unchanged. + *
    + *

    + * In all cases, if the new value is outside the valid range of values for the field + * then a {@code DateTimeException} will be thrown. + *

    + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return a {@code Year} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Year with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + f.checkValidValue(newValue); + switch (f) { + case YEAR_OF_ERA: return Year.of((int) (year < 1 ? 1 - newValue : newValue)); + case YEAR: return Year.of((int) newValue); + case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year)); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year with the specified period added. + *

    + * This method returns a new year based on this year with the specified period added. + * The adder is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #plus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adder the adder to use, not null + * @return a {@code Year} based on this year with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Year plus(TemporalAdder adder) { + return (Year) adder.addTo(this); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public Year plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case YEARS: return plusYears(amountToAdd); + case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10)); + case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); + case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); + case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); + } + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return unit.doPlus(this, amountToAdd); + } + + /** + * Returns a copy of this year with the specified number of years added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToAdd the years to add, may be negative + * @return a {@code Year} based on this year with the period added, not null + * @throws DateTimeException if the result exceeds the supported year range + */ + public Year plusYears(long yearsToAdd) { + if (yearsToAdd == 0) { + return this; + } + return of(YEAR.checkValidIntValue(year + yearsToAdd)); // overflow safe + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year with the specified period subtracted. + *

    + * This method returns a new year based on this year with the specified period subtracted. + * The subtractor is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #minus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param subtractor the subtractor to use, not null + * @return a {@code Year} based on this year with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Year minus(TemporalSubtractor subtractor) { + return (Year) subtractor.subtractFrom(this); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public Year minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + /** + * Returns a copy of this year with the specified number of years subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToSubtract the years to subtract, may be negative + * @return a {@code Year} based on this year with the period subtracted, not null + * @throws DateTimeException if the result exceeds the supported year range + */ + public Year minusYears(long yearsToSubtract) { + return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract)); + } + + //----------------------------------------------------------------------- + /** + * Queries this year using the specified query. + *

    + * This queries this year using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) ISOChrono.INSTANCE; + } else if (query == Queries.precision()) { + return (R) YEARS; + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this year. + *

    + * This returns a temporal object of the same observable type as the input + * with the year changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link ChronoField#YEAR} as the field. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisYear.adjustInto(temporal);
    +     *   temporal = temporal.with(thisYear);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + return temporal.with(YEAR, year); + } + + /** + * Calculates the period between this year and another year in + * terms of the specified unit. + *

    + * This calculates the period between two years in terms of a single unit. + * The start and end points are {@code this} and the specified year. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method must be a {@code Year}. + * For example, the period in decades between two year can be calculated + * using {@code startYear.periodUntil(endYear, DECADES)}. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two years. + * For example, the period in decades between 2012 and 2031 + * will only be one decade as it is one year short of two decades. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, YEARS);   // this method
    +     *   dateTime.plus(YEARS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code YEARS}, {@code DECADES}, {@code CENTURIES}, + * {@code MILLENNIA} and {@code ERAS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endYear the end year, which must be a {@code Year}, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this year and the end year + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long periodUntil(Temporal endYear, TemporalUnit unit) { + if (endYear instanceof Year == false) { + Objects.requireNonNull(endYear, "endYear"); + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + Year end = (Year) endYear; + if (unit instanceof ChronoUnit) { + long yearsUntil = ((long) end.year) - year; // no overflow + switch ((ChronoUnit) unit) { + case YEARS: return yearsUntil; + case DECADES: return yearsUntil / 10; + case CENTURIES: return yearsUntil / 100; + case MILLENNIA: return yearsUntil / 1000; + case ERAS: return end.getLong(ERA) - getLong(ERA); + } + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return unit.between(this, endYear).getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns a date formed from this year at the specified day-of-year. + *

    + * This combines this year and the specified day-of-year to form a {@code LocalDate}. + * The day-of-year value 366 is only valid in a leap year. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfYear the day-of-year to use, not null + * @return the local date formed from this year and the specified date of year, not null + * @throws DateTimeException if the day of year is 366 and this is not a leap year + */ + public LocalDate atDay(int dayOfYear) { + return LocalDate.ofYearDay(year, dayOfYear); + } + + /** + * Returns a year-month formed from this year at the specified month. + *

    + * This combines this year and the specified month to form a {@code YearMonth}. + * All possible combinations of year and month are valid. + *

    + * This method can be used as part of a chain to produce a date: + *

    +     *  LocalDate date = year.atMonth(month).atDay(day);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to use, not null + * @return the year-month formed from this year and the specified month, not null + */ + public YearMonth atMonth(Month month) { + return YearMonth.of(year, month); + } + + /** + * Returns a year-month formed from this year at the specified month. + *

    + * This combines this year and the specified month to form a {@code YearMonth}. + * All possible combinations of year and month are valid. + *

    + * This method can be used as part of a chain to produce a date: + *

    +     *  LocalDate date = year.atMonth(month).atDay(day);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to use, from 1 (January) to 12 (December) + * @return the year-month formed from this year and the specified month, not null + */ + public YearMonth atMonth(int month) { + return YearMonth.of(year, month); + } + + /** + * Returns a date formed from this year at the specified month-day. + *

    + * This combines this year and the specified month-day to form a {@code LocalDate}. + * The month-day value of February 29th is only valid in a leap year. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param monthDay the month-day to use, not null + * @return the local date formed from this year and the specified month-day, not null + * @throws DateTimeException if the month-day is February 29th and this is not a leap year + */ + public LocalDate atMonthDay(MonthDay monthDay) { + return LocalDate.of(year, monthDay.getMonth(), monthDay.getDayOfMonth()); + } + + //----------------------------------------------------------------------- + /** + * Compares this year to another year. + *

    + * The comparison is based on the value of the year. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other year to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(Year other) { + return year - other.year; + } + + /** + * Is this year after the specified year. + * + * @param other the other year to compare to, not null + * @return true if this is after the specified year + */ + public boolean isAfter(Year other) { + return year > other.year; + } + + /** + * Is this year before the specified year. + * + * @param other the other year to compare to, not null + * @return true if this point is before the specified year + */ + public boolean isBefore(Year other) { + return year < other.year; + } + + //----------------------------------------------------------------------- + /** + * Checks if this year is equal to another year. + *

    + * The comparison is based on the time-line position of the years. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other year + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Year) { + return year == ((Year) obj).year; + } + return false; + } + + /** + * A hash code for this year. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return year; + } + + //----------------------------------------------------------------------- + /** + * Outputs this year as a {@code String}. + * + * @return a string representation of this year, not null + */ + @Override + public String toString() { + return Integer.toString(year); + } + + /** + * Outputs this year as a {@code String} using the formatter. + *

    + * This year will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted year string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(4);  // identifies this as a Year
    +     *  out.writeInt(year);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.YEAR_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeInt(year); + } + + static Year readExternal(DataInput in) throws IOException { + return Year.of(in.readInt()); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/YearMonth.java b/jdk/src/share/classes/java/time/temporal/YearMonth.java new file mode 100644 index 00000000000..246112084ca --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/YearMonth.java @@ -0,0 +1,1085 @@ +/* + * 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. + */ + +/* + * 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) 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 java.time.temporal; + +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.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.MONTHS; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.SignStyle; +import java.util.Objects; + +/** + * A year-month in the ISO-8601 calendar system, such as {@code 2007-12}. + *

    + * {@code YearMonth} is an immutable date-time object that represents the combination + * of a year and month. Any field that can be derived from a year and month, such as + * quarter-of-year, can be obtained. + *

    + * This class does not store or represent a day, time or time-zone. + * For example, the value "October 2007" can be stored in a {@code YearMonth}. + *

    + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * For most applications written today, the ISO-8601 rules are entirely suitable. + * However, any application that makes use of historical dates, and requires them + * to be accurate will find the ISO-8601 approach unsuitable. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class YearMonth + implements Temporal, TemporalAdjuster, Comparable, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 4183400860270640070L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendLiteral('-') + .appendValue(MONTH_OF_YEAR, 2) + .toFormatter(); + + /** + * The year. + */ + private final int year; + /** + * The month-of-year, not null. + */ + private final int month; + + //----------------------------------------------------------------------- + /** + * Obtains the current year-month from the system clock in the default time-zone. + *

    + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current year-month. + * The zone and offset will be set based on the time-zone in the clock. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current year-month using the system clock and default time-zone, not null + */ + public static YearMonth now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current year-month from the system clock in the specified time-zone. + *

    + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year-month. + * Specifying the time-zone avoids dependence on the default time-zone. + *

    + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current year-month using the system clock, not null + */ + public static YearMonth now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current year-month from the specified clock. + *

    + * This will query the specified clock to obtain the current year-month. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current year-month, not null + */ + public static YearMonth now(Clock clock) { + final LocalDate now = LocalDate.now(clock); // called once + return YearMonth.of(now.getYear(), now.getMonth()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearMonth} from a year and month. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, not null + * @return the year-month, not null + * @throws DateTimeException if the year value is invalid + */ + public static YearMonth of(int year, Month month) { + Objects.requireNonNull(month, "month"); + return of(year, month.getValue()); + } + + /** + * Obtains an instance of {@code YearMonth} from a year and month. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @return the year-month, not null + * @throws DateTimeException if either field value is invalid + */ + public static YearMonth of(int year, int month) { + YEAR.checkValidValue(year); + MONTH_OF_YEAR.checkValidValue(month); + return new YearMonth(year, month); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearMonth} from a temporal object. + *

    + * A {@code TemporalAccessor} represents some form of date and time information. + * This factory converts the arbitrary temporal object to an instance of {@code YearMonth}. + *

    + * The conversion extracts the {@link ChronoField#YEAR YEAR} and + * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code YearMonth::from}. + * + * @param temporal the temporal object to convert, not null + * @return the year-month, not null + * @throws DateTimeException if unable to convert to a {@code YearMonth} + */ + public static YearMonth from(TemporalAccessor temporal) { + if (temporal instanceof YearMonth) { + return (YearMonth) temporal; + } + try { + if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) { + temporal = LocalDate.from(temporal); + } + return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR)); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}. + *

    + * The string must represent a valid year-month. + * The format must be {@code yyyy-MM}. + * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol. + * + * @param text the text to parse such as "2007-12", not null + * @return the parsed year-month, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static YearMonth parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code YearMonth} from a text string using a specific formatter. + *

    + * The text is parsed using the formatter, returning a year-month. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed year-month, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static YearMonth parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, YearMonth::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param year the year to represent, validated from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, validated from 1 (January) to 12 (December) + */ + private YearMonth(int year, int month) { + this.year = year; + this.month = month; + } + + /** + * Returns a copy of this year-month with the new year and month, checking + * to see if a new object is in fact required. + * + * @param newYear the year to represent, validated from MIN_YEAR to MAX_YEAR + * @param newMonth the month-of-year to represent, validated not null + * @return the year-month, not null + */ + private YearMonth with(int newYear, int newMonth) { + if (year == newYear && month == newMonth) { + return this; + } + return new YearMonth(newYear, newMonth); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this year-month can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * The supported fields are: + *

      + *
    • {@code MONTH_OF_YEAR} + *
    • {@code EPOCH_MONTH} + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this year-month, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == YEAR || field == MONTH_OF_YEAR || + field == EPOCH_MONTH || field == YEAR_OF_ERA || field == ERA; + } + return field != null && field.doIsSupported(this); + } + + /** + * Gets the range of valid values for the specified field. + *

    + * The range object expresses the minimum and maximum valid values for a field. + * This year-month is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field == YEAR_OF_ERA) { + return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); + } + return Temporal.super.range(field); + } + + /** + * Gets the value of the specified field from this year-month as an {@code int}. + *

    + * This queries this year-month for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year-month, except {@code EPOCH_MONTH} which is too + * large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this year-month as a {@code long}. + *

    + * This queries this year-month for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this year-month. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case MONTH_OF_YEAR: return month; + case EPOCH_MONTH: return getEpochMonth(); + case YEAR_OF_ERA: return (year < 1 ? 1 - year : year); + case YEAR: return year; + case ERA: return (year < 1 ? 0 : 1); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doGet(this); + } + + private long getEpochMonth() { + return ((year - 1970) * 12L) + (month - 1); + } + + //----------------------------------------------------------------------- + /** + * Gets the year field. + *

    + * This method returns the primitive {@code int} value for the year. + *

    + * The year returned by this method is proleptic as per {@code get(YEAR)}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return year; + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + *

    + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + */ + public Month getMonth() { + return Month.of(month); + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is a leap year, according to the ISO proleptic + * calendar system rules. + *

    + * This method applies the current rules for leap years across the whole time-line. + * In general, a year is a leap year if it is divisible by four without + * remainder. However, years divisible by 100, are not leap years, with + * the exception of years divisible by 400 which are. + *

    + * For example, 1904 is a leap year it is divisible by 4. + * 1900 was not a leap year as it is divisible by 100, however 2000 was a + * leap year as it is divisible by 400. + *

    + * The calculation is proleptic - applying the same rules into the far future and far past. + * This is historically inaccurate, but is correct for the ISO-8601 standard. + * + * @return true if the year is leap, false otherwise + */ + public boolean isLeapYear() { + return ISOChrono.INSTANCE.isLeapYear(year); + } + + /** + * Checks if the day-of-month is valid for this year-month. + *

    + * This method checks whether this year and month and the input day form + * a valid date. + * + * @param dayOfMonth the day-of-month to validate, from 1 to 31, invalid value returns false + * @return true if the day is valid for this year-month + */ + public boolean isValidDay(int dayOfMonth) { + return dayOfMonth >= 1 && dayOfMonth <= lengthOfMonth(); + } + + /** + * Returns the length of the month, taking account of the year. + *

    + * This returns the length of the month in days. + * For example, a date in January would return 31. + * + * @return the length of the month in days, from 28 to 31 + */ + public int lengthOfMonth() { + return getMonth().length(isLeapYear()); + } + + /** + * Returns the length of the year. + *

    + * This returns the length of the year in days, either 365 or 366. + * + * @return 366 if the year is leap, 365 otherwise + */ + public int lengthOfYear() { + return (isLeapYear() ? 366 : 365); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this year-month. + *

    + * This returns a new {@code YearMonth}, based on this one, with the year-month adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + *

    + * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the year-month to the next month that + * Halley's comet will pass the Earth. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return a {@code YearMonth} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearMonth with(TemporalAdjuster adjuster) { + return (YearMonth) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this year-month with the specified field set to a new value. + *

    + * This returns a new {@code YearMonth}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year or month. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoField} then the adjustment is implemented here. + * The supported fields behave as follows: + *

      + *
    • {@code MONTH_OF_YEAR} - + * Returns a {@code YearMonth} with the specified month-of-year. + * The year will be unchanged. + *
    • {@code EPOCH_MONTH} - + * Returns a {@code YearMonth} with the specified epoch-month. + * This completely replaces the year and month of this object. + *
    • {@code YEAR_OF_ERA} - + * Returns a {@code YearMonth} with the specified year-of-era + * The month and era will be unchanged. + *
    • {@code YEAR} - + * Returns a {@code YearMonth} with the specified year. + * The month will be unchanged. + *
    • {@code ERA} - + * Returns a {@code YearMonth} with the specified era. + * The month and year-of-era will be unchanged. + *
    + *

    + * In all cases, if the new value is outside the valid range of values for the field + * then a {@code DateTimeException} will be thrown. + *

    + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return a {@code YearMonth} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearMonth with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + f.checkValidValue(newValue); + switch (f) { + case MONTH_OF_YEAR: return withMonth((int) newValue); + case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH)); + case YEAR_OF_ERA: return withYear((int) (year < 1 ? 1 - newValue : newValue)); + case YEAR: return withYear((int) newValue); + case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year)); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code YearMonth} with the year altered. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the returned year-month, from MIN_YEAR to MAX_YEAR + * @return a {@code YearMonth} based on this year-month with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public YearMonth withYear(int year) { + YEAR.checkValidValue(year); + return with(year, month); + } + + /** + * Returns a copy of this {@code YearMonth} with the month-of-year altered. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the returned year-month, from 1 (January) to 12 (December) + * @return a {@code YearMonth} based on this year-month with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public YearMonth withMonth(int month) { + MONTH_OF_YEAR.checkValidValue(month); + return with(year, month); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the specified period added. + *

    + * This method returns a new year-month based on this year-month with the specified period added. + * The adder is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAdder} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #plus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param adder the adder to use, not null + * @return a {@code YearMonth} based on this year-month with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearMonth plus(TemporalAdder adder) { + return (YearMonth) adder.addTo(this); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public YearMonth plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case MONTHS: return plusMonths(amountToAdd); + case YEARS: return plusYears(amountToAdd); + case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10)); + case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); + case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); + case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); + } + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return unit.doPlus(this, amountToAdd); + } + + /** + * Returns a copy of this year-month with the specified period in years added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToAdd the years to add, may be negative + * @return a {@code YearMonth} based on this year-month with the years added, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearMonth plusYears(long yearsToAdd) { + if (yearsToAdd == 0) { + return this; + } + int newYear = YEAR.checkValidIntValue(year + yearsToAdd); // safe overflow + return with(newYear, month); + } + + /** + * Returns a copy of this year-month with the specified period in months added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param monthsToAdd the months to add, may be negative + * @return a {@code YearMonth} based on this year-month with the months added, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearMonth plusMonths(long monthsToAdd) { + if (monthsToAdd == 0) { + return this; + } + long monthCount = year * 12L + (month - 1); + long calcMonths = monthCount + monthsToAdd; // safe overflow + int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12)); + int newMonth = (int)Math.floorMod(calcMonths, 12) + 1; + return with(newYear, newMonth); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this year-month with the specified period subtracted. + *

    + * This method returns a new year-month based on this year-month with the specified period subtracted. + * The subtractor is typically {@link java.time.Period} but may be any other type implementing + * the {@link TemporalSubtractor} interface. + * The calculation is delegated to the specified adjuster, which typically calls + * back to {@link #minus(long, TemporalUnit)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param subtractor the subtractor to use, not null + * @return a {@code YearMonth} based on this year-month with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public YearMonth minus(TemporalSubtractor subtractor) { + return (YearMonth) subtractor.subtractFrom(this); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public YearMonth minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + /** + * Returns a copy of this year-month with the specified period in years subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToSubtract the years to subtract, may be negative + * @return a {@code YearMonth} based on this year-month with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearMonth minusYears(long yearsToSubtract) { + return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract)); + } + + /** + * Returns a copy of this year-month with the specified period in months subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param monthsToSubtract the months to subtract, may be negative + * @return a {@code YearMonth} based on this year-month with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public YearMonth minusMonths(long monthsToSubtract) { + return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract)); + } + + //----------------------------------------------------------------------- + /** + * Queries this year-month using the specified query. + *

    + * This queries this year-month using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + *

    + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chrono()) { + return (R) ISOChrono.INSTANCE; + } else if (query == Queries.precision()) { + return (R) MONTHS; + } + return Temporal.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this year-month. + *

    + * This returns a temporal object of the same observable type as the input + * with the year and month changed to be the same as this. + *

    + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * passing {@link ChronoField#EPOCH_MONTH} as the field. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   temporal = thisYearMonth.adjustInto(temporal);
    +     *   temporal = temporal.with(thisYearMonth);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + return temporal.with(EPOCH_MONTH, getEpochMonth()); + } + + /** + * Calculates the period between this year-month and another year-month in + * terms of the specified unit. + *

    + * This calculates the period between two year-months in terms of a single unit. + * The start and end points are {@code this} and the specified year-month. + * The result will be negative if the end is before the start. + * The {@code Temporal} passed to this method must be a {@code YearMonth}. + * For example, the period in years between two year-months can be calculated + * using {@code startYearMonth.periodUntil(endYearMonth, YEARS)}. + *

    + * The calculation returns a whole number, representing the number of + * complete units between the two year-months. + * For example, the period in decades between 2012-06 and 2032-05 + * will only be one decade as it is one month short of two decades. + *

    + * This method operates in association with {@link TemporalUnit#between}. + * The result of this method is a {@code long} representing the amount of + * the specified unit. By contrast, the result of {@code between} is an + * object that can be used directly in addition/subtraction: + *

    +     *   long period = start.periodUntil(end, YEARS);   // this method
    +     *   dateTime.plus(YEARS.between(start, end));      // use in plus/minus
    +     * 
    + *

    + * The calculation is implemented in this method for {@link ChronoUnit}. + * The units {@code MONTHS}, {@code YEARS}, {@code DECADES}, + * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. + * Other {@code ChronoUnit} values will throw an exception. + *

    + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} + * passing {@code this} as the first argument and the input temporal as + * the second argument. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null + * @param unit the unit to measure the period in, not null + * @return the amount of the period between this year-month and the end year-month + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long periodUntil(Temporal endYearMonth, TemporalUnit unit) { + if (endYearMonth instanceof YearMonth == false) { + Objects.requireNonNull(endYearMonth, "endYearMonth"); + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + YearMonth end = (YearMonth) endYearMonth; + if (unit instanceof ChronoUnit) { + long monthsUntil = end.getEpochMonth() - getEpochMonth(); // no overflow + switch ((ChronoUnit) unit) { + case MONTHS: return monthsUntil; + case YEARS: return monthsUntil / 12; + case DECADES: return monthsUntil / 120; + case CENTURIES: return monthsUntil / 1200; + case MILLENNIA: return monthsUntil / 12000; + case ERAS: return end.getLong(ERA) - getLong(ERA); + } + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + return unit.between(this, endYearMonth).getAmount(); + } + + //----------------------------------------------------------------------- + /** + * Returns a date formed from this year-month at the specified day-of-month. + *

    + * This combines this year-month and the specified day-of-month to form a {@code LocalDate}. + * The day-of-month value must be valid for the year-month. + *

    + * This method can be used as part of a chain to produce a date: + *

    +     *  LocalDate date = year.atMonth(month).atDay(day);
    +     * 
    + *

    + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to use, from 1 to 31 + * @return the date formed from this year-month and the specified day, not null + * @throws DateTimeException when the day is invalid for the year-month + * @see #isValidDay(int) + */ + public LocalDate atDay(int dayOfMonth) { + return LocalDate.of(year, month, dayOfMonth); + } + + //----------------------------------------------------------------------- + /** + * Compares this year-month to another year-month. + *

    + * The comparison is based first on the value of the year, then on the value of the month. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other year-month to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(YearMonth other) { + int cmp = (year - other.year); + if (cmp == 0) { + cmp = (month - other.month); + } + return cmp; + } + + /** + * Is this year-month after the specified year-month. + * + * @param other the other year-month to compare to, not null + * @return true if this is after the specified year-month + */ + public boolean isAfter(YearMonth other) { + return compareTo(other) > 0; + } + + /** + * Is this year-month before the specified year-month. + * + * @param other the other year-month to compare to, not null + * @return true if this point is before the specified year-month + */ + public boolean isBefore(YearMonth other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Checks if this year-month is equal to another year-month. + *

    + * The comparison is based on the time-line position of the year-months. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other year-month + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof YearMonth) { + YearMonth other = (YearMonth) obj; + return year == other.year && month == other.month; + } + return false; + } + + /** + * A hash code for this year-month. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return year ^ (month << 27); + } + + //----------------------------------------------------------------------- + /** + * Outputs this year-month as a {@code String}, such as {@code 2007-12}. + *

    + * The output will be in the format {@code yyyy-MM}: + * + * @return a string representation of this year-month, not null + */ + @Override + public String toString() { + int absYear = Math.abs(year); + StringBuilder buf = new StringBuilder(9); + if (absYear < 1000) { + if (year < 0) { + buf.append(year - 10000).deleteCharAt(1); + } else { + buf.append(year + 10000).deleteCharAt(0); + } + } else { + buf.append(year); + } + return buf.append(month < 10 ? "-0" : "-") + .append(month) + .toString(); + } + + /** + * Outputs this year-month as a {@code String} using the formatter. + *

    + * This year-month will be passed to the formatter + * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * + * @param formatter the formatter to use, not null + * @return the formatted year-month string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.print(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * dedicated serialized form. + *

    +     *  out.writeByte(5);  // identifies this as a Year
    +     *  out.writeInt(year);
    +     *  out.writeByte(month);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.YEAR_MONTH_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeInt(year); + out.writeByte(month); + } + + static YearMonth readExternal(DataInput in) throws IOException { + int year = in.readInt(); + byte month = in.readByte(); + return YearMonth.of(year, month); + } + +} diff --git a/jdk/src/share/classes/java/time/temporal/package-info.java b/jdk/src/share/classes/java/time/temporal/package-info.java new file mode 100644 index 00000000000..da9a4b702e8 --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/package-info.java @@ -0,0 +1,214 @@ +/* + * 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. + */ + +/* + * 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. + */ + +/** + *

    + * Access to date and time using fields and units, additional value type classes and + * base support for calendar systems other than the default ISO. + *

    + *

    + * This package expands on the base package to provide additional functionality for + * more powerful use cases. Support is included for: + *

    + *
      + *
    • Units of date-time, such as years, months, days and hours
    • + *
    • Fields of date-time, such as month-of-year, day-of-week or hour-of-day
    • + *
    • Date-time adjustment functions
    • + *
    • Different definitions of weeks
    • + *
    • Alternate calendar systems
    • + *
    • Additional value types
    • + *
    + * + *

    Fields and Units

    + *

    + * Dates and times are expressed in terms of fields and units. + * A unit is used to measure an amount of time, such as years, days or minutes. + * All units implement {@link java.time.temporal.TemporalUnit}. + * The set of well known units is defined in {@link java.time.temporal.ChronoUnit}, such as {@code DAYS}. + * The unit interface is designed to allow applications defined units. + *

    + *

    + * A field is used to express part of a larger date-time, such as year, month-of-year or second-of-minute. + * All fields implement {@link java.time.temporal.TemporalField}. + * The set of well known fields are defined in {@link java.time.temporal.ChronoField}, such as {@code HOUR_OF_DAY}. + * Additional fields are defined by {@link java.time.temporal.JulianFields}, {@link java.time.temporal.WeekFields} + * and {@link java.time.temporal.ISOFields}. + * The field interface is designed to allow applications defined fields. + *

    + *

    + * This package provides tools that allow the units and fields of date and time to be accessed + * in a general way most suited for frameworks. + * {@link java.time.temporal.Temporal} provides the abstraction for date time types that support fields. + * Its methods support getting the value of a field, creating a new date time with the value of + * a field modified, and querying for additional information, typically used to extract the offset or time-zone. + *

    + *

    + * One use of fields in application code is to retrieve fields for which there is no convenience method. + * For example, getting the day-of-month is common enough that there is a method on {@code LocalDate} + * called {@code getDayOfMonth()}. However for more unusual fields it is necessary to use the field. + * For example, {@code date.get(ChronoField.ALIGNED_WEEK_OF_MONTH)}. + * The fields also provide access to the range of valid values. + *

    + * + *

    Adjustment and Query

    + *

    + * A key part of the date-time problem space is adjusting a date to a new, related value, + * such as the "last day of the month", or "next Wednesday". + * These are modeled as functions that adjust a base date-time. + * The functions implement {@link java.time.temporal.TemporalAdjuster} and operate on {@code Temporal}. + * A set of common functions are provided in {@link java.time.temporal.Adjusters}. + * For example, to find the first occurrence of a day-of-week after a given date, use + * {@link java.time.temporal.Adjusters#next(DayOfWeek)}, such as + * {@code date.with(next(MONDAY))}. + * Applications can also define adjusters by implementing {@code TemporalAdjuster}. + *

    + *

    + * There are additional interfaces to model addition to and subtraction from a date-time. + * These are {@link java.time.temporal.TemporalAdder} and {@link java.time.temporal.TemporalSubtractor}. + *

    + *

    + * In addition to adjusting a date-time, an interface is provided to enable querying - + * {@link java.time.temporal.TemporalQuery}. + * The most common implementations of the query interface are method references. + * The {@code from(TemporalAccessor)} methods on major classes can all be used, such as + * {@code LocalDate::from} or {@code Month::from}. + * Further implementations are provided in {@link java.time.temporal.Queries}. + * Applications can also define queries by implementing {@code TemporalQuery}. + *

    + * + *

    Weeks

    + *

    + * Different locales have different definitions of the week. + * For example, in Europe the week typically starts on a Monday, while in the US it starts on a Sunday. + * The {@link java.time.temporal.WeekFields} class models this distinction. + *

    + *

    + * The ISO calendar system defines an additional week-based division of years. + * This defines a year based on whole Monday to Monday weeks. + * This is modeled in {@link java.time.temporal.ISOFields}. + *

    + * + *

    Alternate calendar systems

    + *

    + * The main API is based around the calendar system defined in ISO-8601. + * However, there are other calendar systems, and this package provides basic support for them. + * The alternate calendars are provided in the {@code java.time.calendar} package. + *

    + *

    + * A calendar system is defined by the {@link java.time.temporal.Chrono} interface, + * while a date in a calendar system is defined by the {@link java.time.temporal.ChronoLocalDate} interface. + *

    + *

    + * It is intended that applications use the main API whenever possible, including code to read and write + * from a persistent data store, such as a database, and to send dates and times across a network. + * The "chrono" classes are then used at the user interface level to deal with localized input/output. + *

    + *

    + * Using non-ISO calendar systems in an application introduces significant extra complexity. + * Ensure that the warnings and recommendations in {@code ChronoLocalDate} have been read before + * working with the "chrono" interfaces. + *

    + *

    + * This example creates and uses a date in a non-ISO calendar system. + *

    + *
    + *   // Print the Thai Buddhist date
    + *       ChronoLocalDate<ThaiBuddhistChrono> now1 = ThaiBuddhistChrono.INSTANCE.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.getChrono().getId(),
    + *                 dow, day, month, year);
    + *
    + *   // Enumerate the list of available calendars and print today for each
    + *       Set<Chrono<?>> chronos = Chrono.getAvailableChronologies();
    + *       for (Chrono<?> 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<ThaiBuddhistChrono> first = now1
    + *                 .with(ChronoField.DAY_OF_MONTH, 1)
    + *                 .with(ChronoField.MONTH_OF_YEAR, 1);
    + *       ChronoLocalDate<ThaiBuddhistChrono> last = first
    + *                 .plus(1, ChronoUnit.YEARS)
    + *                 .minus(1, ChronoUnit.DAYS);
    + *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChrono().getId(),
    + *                 first, last);
    + *  
    + * + *

    Package specification

    + *

    + * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface + * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown. + * The Javadoc "@param" definition is used to summarise the null-behavior. + * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method. + *

    + *

    + * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException} + * or a {@link java.time.DateTimeException}. + *

    + * @since JDK1.8 + */ +package java.time.temporal; diff --git a/jdk/src/share/classes/java/time/zone/Ser.java b/jdk/src/share/classes/java/time/zone/Ser.java new file mode 100644 index 00000000000..7d5c0c6719b --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/Ser.java @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/* + * 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) 2011-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 java.time.zone; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.Externalizable; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StreamCorruptedException; +import java.time.ZoneOffset; + +/** + * The shared serialization delegate for this package. + * + *

    Implementation notes

    + * This class is mutable and should be created once per serialization. + * + * @serial include + * @since 1.8 + */ +final class Ser implements Externalizable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -8885321777449118786L; + + /** Type for ZoneRules. */ + static final byte ZRULES = 1; + /** Type for ZoneOffsetTransition. */ + static final byte ZOT = 2; + /** Type for ZoneOffsetTransition. */ + static final byte ZOTRULE = 3; + + /** The type being serialized. */ + private byte type; + /** The object being serialized. */ + private Object object; + + /** + * Constructor for deserialization. + */ + public Ser() { + } + + /** + * Creates an instance for serialization. + * + * @param type the type + * @param object the object + */ + Ser(byte type, Object object) { + this.type = type; + this.object = object; + } + + //----------------------------------------------------------------------- + /** + * Implements the {@code Externalizable} interface to write the object. + * + * @param out the data stream to write to, not null + */ + public void writeExternal(ObjectOutput out) throws IOException { + writeInternal(type, object, out); + } + + static void write(Object object, DataOutput out) throws IOException { + writeInternal(ZRULES, object, out); + } + + private static void writeInternal(byte type, Object object, DataOutput out) throws IOException { + out.writeByte(type); + switch (type) { + case ZRULES: + ((ZoneRules) object).writeExternal(out); + break; + case ZOT: + ((ZoneOffsetTransition) object).writeExternal(out); + break; + case ZOTRULE: + ((ZoneOffsetTransitionRule) object).writeExternal(out); + break; + default: + throw new InvalidClassException("Unknown serialized type"); + } + } + + //----------------------------------------------------------------------- + /** + * Implements the {@code Externalizable} interface to read the object. + * + * @param in the data to read, not null + */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + type = in.readByte(); + object = readInternal(type, in); + } + + static Object read(DataInput in) throws IOException, ClassNotFoundException { + byte type = in.readByte(); + return readInternal(type, in); + } + + private static Object readInternal(byte type, DataInput in) throws IOException, ClassNotFoundException { + switch (type) { + case ZRULES: + return ZoneRules.readExternal(in); + case ZOT: + return ZoneOffsetTransition.readExternal(in); + case ZOTRULE: + return ZoneOffsetTransitionRule.readExternal(in); + default: + throw new StreamCorruptedException("Unknown serialized type"); + } + } + + /** + * Returns the object that will replace this one. + * + * @return the read object, should never be null + */ + private Object readResolve() { + return object; + } + + //----------------------------------------------------------------------- + /** + * Writes the state to the stream. + * + * @param offset the offset, not null + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException { + final int offsetSecs = offset.getTotalSeconds(); + int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127; // compress to -72 to +72 + out.writeByte(offsetByte); + if (offsetByte == 127) { + out.writeInt(offsetSecs); + } + } + + /** + * Reads the state from the stream. + * + * @param in the input stream, not null + * @return the created object, not null + * @throws IOException if an error occurs + */ + static ZoneOffset readOffset(DataInput in) throws IOException { + int offsetByte = in.readByte(); + return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900)); + } + + //----------------------------------------------------------------------- + /** + * Writes the state to the stream. + * + * @param epochSec the epoch seconds, not null + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + static void writeEpochSec(long epochSec, DataOutput out) throws IOException { + if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) { // quarter hours between 1825 and 2300 + int store = (int) ((epochSec + 4575744000L) / 900); + out.writeByte((store >>> 16) & 255); + out.writeByte((store >>> 8) & 255); + out.writeByte(store & 255); + } else { + out.writeByte(255); + out.writeLong(epochSec); + } + } + + /** + * Reads the state from the stream. + * + * @param in the input stream, not null + * @return the epoch seconds, not null + * @throws IOException if an error occurs + */ + static long readEpochSec(DataInput in) throws IOException { + int hiByte = in.readByte() & 255; + if (hiByte == 255) { + return in.readLong(); + } else { + int midByte = in.readByte() & 255; + int loByte = in.readByte() & 255; + long tot = ((hiByte << 16) + (midByte << 8) + loByte); + return (tot * 900) - 4575744000L; + } + } + +} diff --git a/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java b/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java new file mode 100644 index 00000000000..ed81a06dae2 --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java @@ -0,0 +1,298 @@ +/* + * 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. + */ + +/* + * 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 java.time.zone; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.io.StreamCorruptedException; +import java.nio.file.FileSystems; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.time.DateTimeException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.NavigableMap; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.zip.ZipFile; + +/** + * Loads time-zone rules for 'TZDB'. + *

    + * This class is public for the service loader to access. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +final class TzdbZoneRulesProvider extends ZoneRulesProvider { + // service loader seems to need it to be public + + /** + * All the regions that are available. + */ + private final Set regionIds = new CopyOnWriteArraySet<>(); + /** + * All the versions that are available. + */ + private final ConcurrentNavigableMap versions = new ConcurrentSkipListMap<>(); + + /** + * Creates an instance. + * Created by the {@code ServiceLoader}. + * + * @throws ZoneRulesException if unable to load + */ + public TzdbZoneRulesProvider() { + super(); + if (load(ClassLoader.getSystemClassLoader()) == false) { + throw new ZoneRulesException("No time-zone rules found for 'TZDB'"); + } + } + + //----------------------------------------------------------------------- + @Override + protected Set provideZoneIds() { + return new HashSet<>(regionIds); + } + + @Override + protected ZoneRules provideRules(String zoneId) { + Objects.requireNonNull(zoneId, "zoneId"); + ZoneRules rules = versions.lastEntry().getValue().getRules(zoneId); + if (rules == null) { + throw new ZoneRulesException("Unknown time-zone ID: " + zoneId); + } + return rules; + } + + @Override + protected NavigableMap provideVersions(String zoneId) { + TreeMap map = new TreeMap<>(); + for (Version version : versions.values()) { + ZoneRules rules = version.getRules(zoneId); + if (rules != null) { + map.put(version.versionId, rules); + } + } + return map; + } + + //------------------------------------------------------------------------- + /** + * Loads the rules. + * + * @param classLoader the class loader to use, not null + * @return true if updated + * @throws ZoneRulesException if unable to load + */ + private boolean load(ClassLoader classLoader) { + Object updated = Boolean.FALSE; + try { + updated = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws IOException, ClassNotFoundException { + File tzdbJar = null; + // TBD: workaround for now, so test/java/time tests can be + // run against Java runtime that does not have tzdb + String tzdbProp = System.getProperty("java.time.zone.tzdbjar"); + if (tzdbProp != null) { + tzdbJar = new File(tzdbProp); + } else { + String libDir = System.getProperty("java.home") + File.separator + "lib"; + try { + libDir = FileSystems.getDefault().getPath(libDir).toRealPath().toString(); + } catch(Exception e) {} + tzdbJar = new File(libDir, "tzdb.jar"); + } + try (ZipFile zf = new ZipFile(tzdbJar); + DataInputStream dis = new DataInputStream( + zf.getInputStream(zf.getEntry("TZDB.dat")))) { + Iterable loadedVersions = load(dis); + for (Version loadedVersion : loadedVersions) { + if (versions.putIfAbsent(loadedVersion.versionId, loadedVersion) != null) { + throw new DateTimeException( + "Data already loaded for TZDB time-zone rules version: " + + loadedVersion.versionId); + } + } + } + return Boolean.TRUE; + } + }); + } catch (Exception ex) { + throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex); + } + return updated == Boolean.TRUE; + } + + /** + * Loads the rules from a DateInputStream, often in a jar file. + * + * @param dis the DateInputStream to load, not null + * @throws Exception if an error occurs + */ + private Iterable load(DataInputStream dis) throws ClassNotFoundException, IOException { + if (dis.readByte() != 1) { + throw new StreamCorruptedException("File format not recognised"); + } + // group + String groupId = dis.readUTF(); + if ("TZDB".equals(groupId) == false) { + throw new StreamCorruptedException("File format not recognised"); + } + // versions + int versionCount = dis.readShort(); + String[] versionArray = new String[versionCount]; + for (int i = 0; i < versionCount; i++) { + versionArray[i] = dis.readUTF(); + } + // regions + int regionCount = dis.readShort(); + String[] regionArray = new String[regionCount]; + for (int i = 0; i < regionCount; i++) { + regionArray[i] = dis.readUTF(); + } + regionIds.addAll(Arrays.asList(regionArray)); + // rules + int ruleCount = dis.readShort(); + Object[] ruleArray = new Object[ruleCount]; + for (int i = 0; i < ruleCount; i++) { + byte[] bytes = new byte[dis.readShort()]; + dis.readFully(bytes); + ruleArray[i] = bytes; + } + AtomicReferenceArray ruleData = new AtomicReferenceArray<>(ruleArray); + // link version-region-rules + Set versionSet = new HashSet(versionCount); + for (int i = 0; i < versionCount; i++) { + int versionRegionCount = dis.readShort(); + String[] versionRegionArray = new String[versionRegionCount]; + short[] versionRulesArray = new short[versionRegionCount]; + for (int j = 0; j < versionRegionCount; j++) { + versionRegionArray[j] = regionArray[dis.readShort()]; + versionRulesArray[j] = dis.readShort(); + } + versionSet.add(new Version(versionArray[i], versionRegionArray, versionRulesArray, ruleData)); + } + return versionSet; + } + + @Override + public String toString() { + return "TZDB"; + } + + //----------------------------------------------------------------------- + /** + * A version of the TZDB rules. + */ + static class Version { + private final String versionId; + private final String[] regionArray; + private final short[] ruleIndices; + private final AtomicReferenceArray ruleData; + + Version(String versionId, String[] regionIds, short[] ruleIndices, AtomicReferenceArray ruleData) { + this.ruleData = ruleData; + this.versionId = versionId; + this.regionArray = regionIds; + this.ruleIndices = ruleIndices; + } + + ZoneRules getRules(String regionId) { + int regionIndex = Arrays.binarySearch(regionArray, regionId); + if (regionIndex < 0) { + return null; + } + try { + return createRule(ruleIndices[regionIndex]); + } catch (Exception ex) { + throw new ZoneRulesException("Invalid binary time-zone data: TZDB:" + regionId + ", version: " + versionId, ex); + } + } + + ZoneRules createRule(short index) throws Exception { + Object obj = ruleData.get(index); + if (obj instanceof byte[]) { + byte[] bytes = (byte[]) obj; + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes)); + obj = Ser.read(dis); + ruleData.set(index, obj); + } + return (ZoneRules) obj; + } + + @Override + public String toString() { + return versionId; + } + } + +} diff --git a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java new file mode 100644 index 00000000000..6d080aba27d --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java @@ -0,0 +1,431 @@ +/* + * 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. + */ + +/* + * 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 java.time.zone; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.Serializable; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A transition between two offsets caused by a discontinuity in the local time-line. + *

    + * A transition between two offsets is normally the result of a daylight savings cutover. + * The discontinuity is normally a gap in spring and an overlap in autumn. + * {@code ZoneOffsetTransition} models the transition between the two offsets. + *

    + * Gaps occur where there are local date-times that simply do not not exist. + * An example would be when the offset changes from {@code +03:00} to {@code +04:00}. + * This might be described as 'the clocks will move forward one hour tonight at 1am'. + *

    + * Overlaps occur where there are local date-times that exist twice. + * An example would be when the offset changes from {@code +04:00} to {@code +03:00}. + * This might be described as 'the clocks will move back one hour tonight at 2am'. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ZoneOffsetTransition + implements Comparable, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -6946044323557704546L; + /** + * The local transition date-time at the transition. + */ + private final LocalDateTime transition; + /** + * The offset before transition. + */ + private final ZoneOffset offsetBefore; + /** + * The offset after transition. + */ + private final ZoneOffset offsetAfter; + + //----------------------------------------------------------------------- + /** + * Obtains an instance defining a transition between two offsets. + *

    + * Applications should normally obtain an instance from {@link ZoneRules}. + * This factory is only intended for use when creating {@link ZoneRules}. + * + * @param transition the transition date-time at the transition, which never + * actually occurs, expressed local to the before offset, not null + * @param offsetBefore the offset before the transition, not null + * @param offsetAfter the offset at and after the transition, not null + * @return the transition, not null + * @throws IllegalArgumentException if {@code offsetBefore} and {@code offsetAfter} + * are equal, or {@code transition.getNano()} returns non-zero value + */ + public static ZoneOffsetTransition of(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) { + Objects.requireNonNull(transition, "transition"); + Objects.requireNonNull(offsetBefore, "offsetBefore"); + Objects.requireNonNull(offsetAfter, "offsetAfter"); + if (offsetBefore.equals(offsetAfter)) { + throw new IllegalArgumentException("Offsets must not be equal"); + } + if (transition.getNano() != 0) { + throw new IllegalArgumentException("Nano-of-second must be zero"); + } + return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter); + } + + /** + * Creates an instance defining a transition between two offsets. + * + * @param transition the transition date-time with the offset before the transition, not null + * @param offsetBefore the offset before the transition, not null + * @param offsetAfter the offset at and after the transition, not null + */ + ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) { + this.transition = transition; + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + /** + * Creates an instance from epoch-second and offsets. + * + * @param epochSecond the transition epoch-second + * @param offsetBefore the offset before the transition, not null + * @param offsetAfter the offset at and after the transition, not null + */ + ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) { + this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore); + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + //----------------------------------------------------------------------- + /** + * Uses a serialization delegate. + * + * @return the replacing object, not null + */ + private Object writeReplace() { + return new Ser(Ser.ZOT, this); + } + + /** + * Writes the state to the stream. + * + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + void writeExternal(DataOutput out) throws IOException { + Ser.writeEpochSec(toEpochSecond(), out); + Ser.writeOffset(offsetBefore, out); + Ser.writeOffset(offsetAfter, out); + } + + /** + * Reads the state from the stream. + * + * @param in the input stream, not null + * @return the created object, not null + * @throws IOException if an error occurs + */ + static ZoneOffsetTransition readExternal(DataInput in) throws IOException { + long epochSecond = Ser.readEpochSec(in); + ZoneOffset before = Ser.readOffset(in); + ZoneOffset after = Ser.readOffset(in); + if (before.equals(after)) { + throw new IllegalArgumentException("Offsets must not be equal"); + } + return new ZoneOffsetTransition(epochSecond, before, after); + } + + //----------------------------------------------------------------------- + /** + * Gets the transition instant. + *

    + * This is the instant of the discontinuity, which is defined as the first + * instant that the 'after' offset applies. + *

    + * The methods {@link #getInstant()}, {@link #getDateTimeBefore()} and {@link #getDateTimeAfter()} + * all represent the same instant. + * + * @return the transition instant, not null + */ + public Instant getInstant() { + return transition.toInstant(offsetBefore); + } + + /** + * Gets the transition instant as an epoch second. + * + * @return the transition epoch second + */ + public long toEpochSecond() { + return transition.toEpochSecond(offsetBefore); + } + + //------------------------------------------------------------------------- + /** + * Gets the local transition date-time, as would be expressed with the 'before' offset. + *

    + * This is the date-time where the discontinuity begins expressed with the 'before' offset. + * At this instant, the 'after' offset is actually used, therefore the combination of this + * date-time and the 'before' offset will never occur. + *

    + * The combination of the 'before' date-time and offset represents the same instant + * as the 'after' date-time and offset. + * + * @return the transition date-time expressed with the before offset, not null + */ + public LocalDateTime getDateTimeBefore() { + return transition; + } + + /** + * Gets the local transition date-time, as would be expressed with the 'after' offset. + *

    + * This is the first date-time after the discontinuity, when the new offset applies. + *

    + * The combination of the 'before' date-time and offset represents the same instant + * as the 'after' date-time and offset. + * + * @return the transition date-time expressed with the after offset, not null + */ + public LocalDateTime getDateTimeAfter() { + return transition.plusSeconds(getDurationSeconds()); + } + + /** + * Gets the offset before the transition. + *

    + * This is the offset in use before the instant of the transition. + * + * @return the offset before the transition, not null + */ + public ZoneOffset getOffsetBefore() { + return offsetBefore; + } + + /** + * Gets the offset after the transition. + *

    + * This is the offset in use on and after the instant of the transition. + * + * @return the offset after the transition, not null + */ + public ZoneOffset getOffsetAfter() { + return offsetAfter; + } + + /** + * Gets the duration of the transition. + *

    + * In most cases, the transition duration is one hour, however this is not always the case. + * The duration will be positive for a gap and negative for an overlap. + * Time-zones are second-based, so the nanosecond part of the duration will be zero. + * + * @return the duration of the transition, positive for gaps, negative for overlaps + */ + public Duration getDuration() { + return Duration.ofSeconds(getDurationSeconds()); + } + + /** + * Gets the duration of the transition in seconds. + * + * @return the duration in seconds + */ + private int getDurationSeconds() { + return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds(); + } + + /** + * Does this transition represent a gap in the local time-line. + *

    + * Gaps occur where there are local date-times that simply do not not exist. + * An example would be when the offset changes from {@code +01:00} to {@code +02:00}. + * This might be described as 'the clocks will move forward one hour tonight at 1am'. + * + * @return true if this transition is a gap, false if it is an overlap + */ + public boolean isGap() { + return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds(); + } + + /** + * Does this transition represent a gap in the local time-line. + *

    + * Overlaps occur where there are local date-times that exist twice. + * An example would be when the offset changes from {@code +02:00} to {@code +01:00}. + * This might be described as 'the clocks will move back one hour tonight at 2am'. + * + * @return true if this transition is an overlap, false if it is a gap + */ + public boolean isOverlap() { + return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds(); + } + + /** + * Checks if the specified offset is valid during this transition. + *

    + * This checks to see if the given offset will be valid at some point in the transition. + * A gap will always return false. + * An overlap will return true if the offset is either the before or after offset. + * + * @param offset the offset to check, null returns false + * @return true if the offset is valid during the transition + */ + public boolean isValidOffset(ZoneOffset offset) { + return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset)); + } + + /** + * Gets the valid offsets during this transition. + *

    + * A gap will return an empty list, while an overlap will return both offsets. + * + * @return the list of valid offsets + */ + List getValidOffsets() { + if (isGap()) { + return Collections.emptyList(); + } + return Arrays.asList(getOffsetBefore(), getOffsetAfter()); + } + + //----------------------------------------------------------------------- + /** + * Compares this transition to another based on the transition instant. + *

    + * This compares the instants of each transition. + * The offsets are ignored, making this order inconsistent with equals. + * + * @param transition the transition to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(ZoneOffsetTransition transition) { + return this.getInstant().compareTo(transition.getInstant()); + } + + //----------------------------------------------------------------------- + /** + * Checks if this object equals another. + *

    + * The entire state of the object is compared. + * + * @param other the other object to compare to, null returns false + * @return true if equal + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other instanceof ZoneOffsetTransition) { + ZoneOffsetTransition d = (ZoneOffsetTransition) other; + return transition.equals(d.transition) && + offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter); + } + return false; + } + + /** + * Returns a suitable hash code. + * + * @return the hash code + */ + @Override + public int hashCode() { + return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16); + } + + //----------------------------------------------------------------------- + /** + * Returns a string describing this object. + * + * @return a string for debugging, not null + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("Transition[") + .append(isGap() ? "Gap" : "Overlap") + .append(" at ") + .append(transition) + .append(offsetBefore) + .append(" to ") + .append(offsetAfter) + .append(']'); + return buf.toString(); + } + +} diff --git a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java new file mode 100644 index 00000000000..4b6f7e90722 --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java @@ -0,0 +1,575 @@ +/* + * 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. + */ + +/* + * 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 java.time.zone; + +import static java.time.temporal.Adjusters.nextOrSame; +import static java.time.temporal.Adjusters.previousOrSame; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.Serializable; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.temporal.ISOChrono; +import java.util.Objects; + +/** + * A rule expressing how to create a transition. + *

    + * This class allows rules for identifying future transitions to be expressed. + * A rule might be written in many forms: + *

      + *
    • the 16th March + *
    • the Sunday on or after the 16th March + *
    • the Sunday on or before the 16th March + *
    • the last Sunday in February + *

    + * These different rule types can be expressed and queried. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ZoneOffsetTransitionRule implements Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 6889046316657758795L; + + /** + * The month of the month-day of the first day of the cutover week. + * The actual date will be adjusted by the dowChange field. + */ + private final Month month; + /** + * The day-of-month of the month-day of the cutover week. + * If positive, it is the start of the week where the cutover can occur. + * If negative, it represents the end of the week where cutover can occur. + * The value is the number of days from the end of the month, such that + * {@code -1} is the last day of the month, {@code -2} is the second + * to last day, and so on. + */ + private final byte dom; + /** + * The cutover day-of-week, null to retain the day-of-month. + */ + private final DayOfWeek dow; + /** + * The cutover time in the 'before' offset. + */ + private final LocalTime time; + /** + * Whether the cutover time is midnight at the end of day. + */ + private final boolean timeEndOfDay; + /** + * The definition of how the local time should be interpreted. + */ + private final TimeDefinition timeDefinition; + /** + * The standard offset at the cutover. + */ + private final ZoneOffset standardOffset; + /** + * The offset before the cutover. + */ + private final ZoneOffset offsetBefore; + /** + * The offset after the cutover. + */ + private final ZoneOffset offsetAfter; + + /** + * Obtains an instance defining the yearly rule to create transitions between two offsets. + *

    + * Applications should normally obtain an instance from {@link ZoneRules}. + * This factory is only intended for use when creating {@link ZoneRules}. + * + * @param month the month of the month-day of the first day of the cutover week, not null + * @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that + * day or later, negative if the week is that day or earlier, counting from the last day of the month, + * from -28 to 31 excluding 0 + * @param dayOfWeek the required day-of-week, null if the month-day should not be changed + * @param time the cutover time in the 'before' offset, not null + * @param timeEndOfDay whether the time is midnight at the end of day + * @param timeDefnition how to interpret the cutover + * @param standardOffset the standard offset in force at the cutover, not null + * @param offsetBefore the offset before the cutover, not null + * @param offsetAfter the offset after the cutover, not null + * @return the rule, not null + * @throws IllegalArgumentException if the day of month indicator is invalid + * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight + */ + public static ZoneOffsetTransitionRule of( + Month month, + int dayOfMonthIndicator, + DayOfWeek dayOfWeek, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefnition, + ZoneOffset standardOffset, + ZoneOffset offsetBefore, + ZoneOffset offsetAfter) { + Objects.requireNonNull(month, "month"); + Objects.requireNonNull(time, "time"); + Objects.requireNonNull(timeDefnition, "timeDefnition"); + Objects.requireNonNull(standardOffset, "standardOffset"); + Objects.requireNonNull(offsetBefore, "offsetBefore"); + Objects.requireNonNull(offsetAfter, "offsetAfter"); + if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) { + throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero"); + } + if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) { + throw new IllegalArgumentException("Time must be midnight when end of day flag is true"); + } + return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter); + } + + /** + * Creates an instance defining the yearly rule to create transitions between two offsets. + * + * @param month the month of the month-day of the first day of the cutover week, not null + * @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that + * day or later, negative if the week is that day or earlier, counting from the last day of the month, + * from -28 to 31 excluding 0 + * @param dayOfWeek the required day-of-week, null if the month-day should not be changed + * @param time the cutover time in the 'before' offset, not null + * @param timeEndOfDay whether the time is midnight at the end of day + * @param timeDefnition how to interpret the cutover + * @param standardOffset the standard offset in force at the cutover, not null + * @param offsetBefore the offset before the cutover, not null + * @param offsetAfter the offset after the cutover, not null + * @throws IllegalArgumentException if the day of month indicator is invalid + * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight + */ + ZoneOffsetTransitionRule( + Month month, + int dayOfMonthIndicator, + DayOfWeek dayOfWeek, + LocalTime time, + boolean timeEndOfDay, + TimeDefinition timeDefnition, + ZoneOffset standardOffset, + ZoneOffset offsetBefore, + ZoneOffset offsetAfter) { + this.month = month; + this.dom = (byte) dayOfMonthIndicator; + this.dow = dayOfWeek; + this.time = time; + this.timeEndOfDay = timeEndOfDay; + this.timeDefinition = timeDefnition; + this.standardOffset = standardOffset; + this.offsetBefore = offsetBefore; + this.offsetAfter = offsetAfter; + } + + //----------------------------------------------------------------------- + /** + * Uses a serialization delegate. + * + * @return the replacing object, not null + */ + private Object writeReplace() { + return new Ser(Ser.ZOTRULE, this); + } + + /** + * Writes the state to the stream. + * + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + void writeExternal(DataOutput out) throws IOException { + final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay()); + final int stdOffset = standardOffset.getTotalSeconds(); + final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset; + final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset; + final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31); + final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255); + final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3); + final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3); + final int dowByte = (dow == null ? 0 : dow.getValue()); + int b = (month.getValue() << 28) + // 4 bits + ((dom + 32) << 22) + // 6 bits + (dowByte << 19) + // 3 bits + (timeByte << 14) + // 5 bits + (timeDefinition.ordinal() << 12) + // 2 bits + (stdOffsetByte << 4) + // 8 bits + (beforeByte << 2) + // 2 bits + afterByte; // 2 bits + out.writeInt(b); + if (timeByte == 31) { + out.writeInt(timeSecs); + } + if (stdOffsetByte == 255) { + out.writeInt(stdOffset); + } + if (beforeByte == 3) { + out.writeInt(offsetBefore.getTotalSeconds()); + } + if (afterByte == 3) { + out.writeInt(offsetAfter.getTotalSeconds()); + } + } + + /** + * Reads the state from the stream. + * + * @param in the input stream, not null + * @return the created object, not null + * @throws IOException if an error occurs + */ + static ZoneOffsetTransitionRule readExternal(DataInput in) throws IOException { + int data = in.readInt(); + Month month = Month.of(data >>> 28); + int dom = ((data & (63 << 22)) >>> 22) - 32; + int dowByte = (data & (7 << 19)) >>> 19; + DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte); + int timeByte = (data & (31 << 14)) >>> 14; + TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12]; + int stdByte = (data & (255 << 4)) >>> 4; + int beforeByte = (data & (3 << 2)) >>> 2; + int afterByte = (data & 3); + LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(in.readInt()) : LocalTime.of(timeByte % 24, 0)); + ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900)); + ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800)); + ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800)); + return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after); + } + + //----------------------------------------------------------------------- + /** + * Gets the month of the transition. + *

    + * If the rule defines an exact date then the month is the month of that date. + *

    + * If the rule defines a week where the transition might occur, then the month + * if the month of either the earliest or latest possible date of the cutover. + * + * @return the month of the transition, not null + */ + public Month getMonth() { + return month; + } + + /** + * Gets the indicator of the day-of-month of the transition. + *

    + * If the rule defines an exact date then the day is the month of that date. + *

    + * If the rule defines a week where the transition might occur, then the day + * defines either the start of the end of the transition week. + *

    + * If the value is positive, then it represents a normal day-of-month, and is the + * earliest possible date that the transition can be. + * The date may refer to 29th February which should be treated as 1st March in non-leap years. + *

    + * If the value is negative, then it represents the number of days back from the + * end of the month where {@code -1} is the last day of the month. + * In this case, the day identified is the latest possible date that the transition can be. + * + * @return the day-of-month indicator, from -28 to 31 excluding 0 + */ + public int getDayOfMonthIndicator() { + return dom; + } + + /** + * Gets the day-of-week of the transition. + *

    + * If the rule defines an exact date then this returns null. + *

    + * If the rule defines a week where the cutover might occur, then this method + * returns the day-of-week that the month-day will be adjusted to. + * If the day is positive then the adjustment is later. + * If the day is negative then the adjustment is earlier. + * + * @return the day-of-week that the transition occurs, null if the rule defines an exact date + */ + public DayOfWeek getDayOfWeek() { + return dow; + } + + /** + * Gets the local time of day of the transition which must be checked with + * {@link #isMidnightEndOfDay()}. + *

    + * The time is converted into an instant using the time definition. + * + * @return the local time of day of the transition, not null + */ + public LocalTime getLocalTime() { + return time; + } + + /** + * Is the transition local time midnight at the end of day. + *

    + * The transition may be represented as occurring at 24:00. + * + * @return whether a local time of midnight is at the start or end of the day + */ + public boolean isMidnightEndOfDay() { + return timeEndOfDay; + } + + /** + * Gets the time definition, specifying how to convert the time to an instant. + *

    + * The local time can be converted to an instant using the standard offset, + * the wall offset or UTC. + * + * @return the time definition, not null + */ + public TimeDefinition getTimeDefinition() { + return timeDefinition; + } + + /** + * Gets the standard offset in force at the transition. + * + * @return the standard offset, not null + */ + public ZoneOffset getStandardOffset() { + return standardOffset; + } + + /** + * Gets the offset before the transition. + * + * @return the offset before, not null + */ + public ZoneOffset getOffsetBefore() { + return offsetBefore; + } + + /** + * Gets the offset after the transition. + * + * @return the offset after, not null + */ + public ZoneOffset getOffsetAfter() { + return offsetAfter; + } + + //----------------------------------------------------------------------- + /** + * Creates a transition instance for the specified year. + *

    + * Calculations are performed using the ISO-8601 chronology. + * + * @param year the year to create a transition for, not null + * @return the transition instance, not null + */ + public ZoneOffsetTransition createTransition(int year) { + LocalDate date; + if (dom < 0) { + date = LocalDate.of(year, month, month.length(ISOChrono.INSTANCE.isLeapYear(year)) + 1 + dom); + if (dow != null) { + date = date.with(previousOrSame(dow)); + } + } else { + date = LocalDate.of(year, month, dom); + if (dow != null) { + date = date.with(nextOrSame(dow)); + } + } + if (timeEndOfDay) { + date = date.plusDays(1); + } + LocalDateTime localDT = LocalDateTime.of(date, time); + LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore); + return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter); + } + + //----------------------------------------------------------------------- + /** + * Checks if this object equals another. + *

    + * The entire state of the object is compared. + * + * @param otherRule the other object to compare to, null returns false + * @return true if equal + */ + @Override + public boolean equals(Object otherRule) { + if (otherRule == this) { + return true; + } + if (otherRule instanceof ZoneOffsetTransitionRule) { + ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule; + return month == other.month && dom == other.dom && dow == other.dow && + timeDefinition == other.timeDefinition && + time.equals(other.time) && + timeEndOfDay == other.timeEndOfDay && + standardOffset.equals(other.standardOffset) && + offsetBefore.equals(other.offsetBefore) && + offsetAfter.equals(other.offsetAfter); + } + return false; + } + + /** + * Returns a suitable hash code. + * + * @return the hash code + */ + @Override + public int hashCode() { + int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) + + (month.ordinal() << 11) + ((dom + 32) << 5) + + ((dow == null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal()); + return hash ^ standardOffset.hashCode() ^ + offsetBefore.hashCode() ^ offsetAfter.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Returns a string describing this object. + * + * @return a string for debugging, not null + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("TransitionRule[") + .append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ") + .append(offsetBefore).append(" to ").append(offsetAfter).append(", "); + if (dow != null) { + if (dom == -1) { + buf.append(dow.name()).append(" on or before last day of ").append(month.name()); + } else if (dom < 0) { + buf.append(dow.name()).append(" on or before last day minus ").append(-dom - 1).append(" of ").append(month.name()); + } else { + buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom); + } + } else { + buf.append(month.name()).append(' ').append(dom); + } + buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString()) + .append(" ").append(timeDefinition) + .append(", standard offset ").append(standardOffset) + .append(']'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * A definition of the way a local time can be converted to the actual + * transition date-time. + *

    + * Time zone rules are expressed in one of three ways: + *

      + *
    • Relative to UTC
    • + *
    • Relative to the standard offset in force
    • + *
    • Relative to the wall offset (what you would see on a clock on the wall)
    • + *

    + */ + public static enum TimeDefinition { + /** The local date-time is expressed in terms of the UTC offset. */ + UTC, + /** The local date-time is expressed in terms of the wall offset. */ + WALL, + /** The local date-time is expressed in terms of the standard offset. */ + STANDARD; + + /** + * Converts the specified local date-time to the local date-time actually + * seen on a wall clock. + *

    + * This method converts using the type of this enum. + * The output is defined relative to the 'before' offset of the transition. + *

    + * The UTC type uses the UTC offset. + * The STANDARD type uses the standard offset. + * The WALL type returns the input date-time. + * The result is intended for use with the wall-offset. + * + * @param dateTime the local date-time, not null + * @param standardOffset the standard offset, not null + * @param wallOffset the wall offset, not null + * @return the date-time relative to the wall/before offset, not null + */ + public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) { + switch (this) { + case UTC: { + int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds(); + return dateTime.plusSeconds(difference); + } + case STANDARD: { + int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds(); + return dateTime.plusSeconds(difference); + } + default: // WALL + return dateTime; + } + } + } + +} diff --git a/jdk/src/share/classes/java/time/zone/ZoneRules.java b/jdk/src/share/classes/java/time/zone/ZoneRules.java new file mode 100644 index 00000000000..159d6e0d36a --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/ZoneRules.java @@ -0,0 +1,959 @@ +/* + * 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. + */ + +/* + * 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 java.time.zone; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.Serializable; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.temporal.Year; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * The rules defining how the zone offset varies for a single time-zone. + *

    + * The rules model all the historic and future transitions for a time-zone. + * {@link ZoneOffsetTransition} is used for known transitions, typically historic. + * {@link ZoneOffsetTransitionRule} is used for future transitions that are based + * on the result of an algorithm. + *

    + * The rules are loaded via {@link ZoneRulesProvider} using a {@link ZoneId}. + * The same rules may be shared internally between multiple zone IDs. + *

    + * Serializing an instance of {@code ZoneRules} will store the entire set of rules. + * It does not store the zone ID as it is not part of the state of this object. + *

    + * A rule implementation may or may not store full information about historic + * and future transitions, and the information stored is only as accurate as + * that supplied to the implementation by the rules provider. + * Applications should treat the data provided as representing the best information + * available to the implementation of this rule. + * + *

    Specification for implementors

    + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class ZoneRules implements Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 3044319355680032515L; + /** + * The last year to have its transitions cached. + */ + private static final int LAST_CACHED_YEAR = 2100; + + /** + * The transitions between standard offsets (epoch seconds), sorted. + */ + private final long[] standardTransitions; + /** + * The standard offsets. + */ + private final ZoneOffset[] standardOffsets; + /** + * The transitions between instants (epoch seconds), sorted. + */ + private final long[] savingsInstantTransitions; + /** + * The transitions between local date-times, sorted. + * This is a paired array, where the first entry is the start of the transition + * and the second entry is the end of the transition. + */ + private final LocalDateTime[] savingsLocalTransitions; + /** + * The wall offsets. + */ + private final ZoneOffset[] wallOffsets; + /** + * The last rule. + */ + private final ZoneOffsetTransitionRule[] lastRules; + /** + * The map of recent transitions. + */ + private final ConcurrentMap lastRulesCache = + new ConcurrentHashMap(); + /** + * The zero-length long array. + */ + private static final long[] EMPTY_LONG_ARRAY = new long[0]; + /** + * The zero-length lastrules array. + */ + private static final ZoneOffsetTransitionRule[] EMPTY_LASTRULES = + new ZoneOffsetTransitionRule[0]; + /** + * The zero-length ldt array. + */ + private static final LocalDateTime[] EMPTY_LDT_ARRAY = new LocalDateTime[0]; + + /** + * Obtains an instance of a ZoneRules. + * + * @param baseStandardOffset the standard offset to use before legal rules were set, not null + * @param baseWallOffset the wall offset to use before legal rules were set, not null + * @param standardOffsetTransitionList the list of changes to the standard offset, not null + * @param transitionList the list of transitions, not null + * @param lastRules the recurring last rules, size 16 or less, not null + * @return the zone rules, not null + */ + public static ZoneRules of(ZoneOffset baseStandardOffset, + ZoneOffset baseWallOffset, + List standardOffsetTransitionList, + List transitionList, + List lastRules) { + Objects.requireNonNull(baseStandardOffset, "baseStandardOffset"); + Objects.requireNonNull(baseWallOffset, "baseWallOffset"); + Objects.requireNonNull(standardOffsetTransitionList, "standardOffsetTransitionList"); + Objects.requireNonNull(transitionList, "transitionList"); + Objects.requireNonNull(lastRules, "lastRules"); + return new ZoneRules(baseStandardOffset, baseWallOffset, + standardOffsetTransitionList, transitionList, lastRules); + } + + /** + * Obtains an instance of ZoneRules that has fixed zone rules. + * + * @param offset the offset this fixed zone rules is based on, not null + * @return the zone rules, not null + * @see #isFixedOffset() + */ + public static ZoneRules of(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + return new ZoneRules(offset); + } + + /** + * Creates an instance. + * + * @param baseStandardOffset the standard offset to use before legal rules were set, not null + * @param baseWallOffset the wall offset to use before legal rules were set, not null + * @param standardOffsetTransitionList the list of changes to the standard offset, not null + * @param transitionList the list of transitions, not null + * @param lastRules the recurring last rules, size 16 or less, not null + */ + ZoneRules(ZoneOffset baseStandardOffset, + ZoneOffset baseWallOffset, + List standardOffsetTransitionList, + List transitionList, + List lastRules) { + super(); + + // convert standard transitions + + this.standardTransitions = new long[standardOffsetTransitionList.size()]; + + this.standardOffsets = new ZoneOffset[standardOffsetTransitionList.size() + 1]; + this.standardOffsets[0] = baseStandardOffset; + for (int i = 0; i < standardOffsetTransitionList.size(); i++) { + this.standardTransitions[i] = standardOffsetTransitionList.get(i).toEpochSecond(); + this.standardOffsets[i + 1] = standardOffsetTransitionList.get(i).getOffsetAfter(); + } + + // convert savings transitions to locals + List localTransitionList = new ArrayList<>(); + List localTransitionOffsetList = new ArrayList<>(); + localTransitionOffsetList.add(baseWallOffset); + for (ZoneOffsetTransition trans : transitionList) { + if (trans.isGap()) { + localTransitionList.add(trans.getDateTimeBefore()); + localTransitionList.add(trans.getDateTimeAfter()); + } else { + localTransitionList.add(trans.getDateTimeAfter()); + localTransitionList.add(trans.getDateTimeBefore()); + } + localTransitionOffsetList.add(trans.getOffsetAfter()); + } + this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]); + this.wallOffsets = localTransitionOffsetList.toArray(new ZoneOffset[localTransitionOffsetList.size()]); + + // convert savings transitions to instants + this.savingsInstantTransitions = new long[transitionList.size()]; + for (int i = 0; i < transitionList.size(); i++) { + this.savingsInstantTransitions[i] = transitionList.get(i).toEpochSecond(); + } + + // last rules + if (lastRules.size() > 16) { + throw new IllegalArgumentException("Too many transition rules"); + } + this.lastRules = lastRules.toArray(new ZoneOffsetTransitionRule[lastRules.size()]); + } + + /** + * Constructor. + * + * @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 ZoneRules(long[] standardTransitions, + ZoneOffset[] standardOffsets, + long[] savingsInstantTransitions, + ZoneOffset[] wallOffsets, + ZoneOffsetTransitionRule[] lastRules) { + super(); + + this.standardTransitions = standardTransitions; + this.standardOffsets = standardOffsets; + this.savingsInstantTransitions = savingsInstantTransitions; + this.wallOffsets = wallOffsets; + this.lastRules = lastRules; + + if (savingsInstantTransitions.length == 0) { + this.savingsLocalTransitions = EMPTY_LDT_ARRAY; + } else { + // convert savings transitions to locals + List localTransitionList = new ArrayList<>(); + for (int i = 0; i < savingsInstantTransitions.length; i++) { + ZoneOffset before = wallOffsets[i]; + ZoneOffset after = wallOffsets[i + 1]; + ZoneOffsetTransition trans = new ZoneOffsetTransition(savingsInstantTransitions[i], before, after); + if (trans.isGap()) { + localTransitionList.add(trans.getDateTimeBefore()); + localTransitionList.add(trans.getDateTimeAfter()); + } else { + localTransitionList.add(trans.getDateTimeAfter()); + localTransitionList.add(trans.getDateTimeBefore()); + } + } + this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]); + } + } + + /** + * Creates an instance of ZoneRules that has fixed zone rules. + * + * @param offset the offset this fixed zone rules is based on, not null + * @return the zone rules, not null + * @see #isFixedOffset() + */ + private ZoneRules(ZoneOffset offset) { + this.standardOffsets = new ZoneOffset[1]; + this.standardOffsets[0] = offset; + this.standardTransitions = EMPTY_LONG_ARRAY; + this.savingsInstantTransitions = EMPTY_LONG_ARRAY; + this.savingsLocalTransitions = EMPTY_LDT_ARRAY; + this.wallOffsets = standardOffsets; + this.lastRules = EMPTY_LASTRULES; + } + + /** + * Uses a serialization delegate. + * + * @return the replacing object, not null + */ + private Object writeReplace() { + return new Ser(Ser.ZRULES, this); + } + + /** + * Writes the state to the stream. + * + * @param out the output stream, not null + * @throws IOException if an error occurs + */ + void writeExternal(DataOutput out) throws IOException { + out.writeInt(standardTransitions.length); + for (long trans : standardTransitions) { + Ser.writeEpochSec(trans, out); + } + for (ZoneOffset offset : standardOffsets) { + Ser.writeOffset(offset, out); + } + out.writeInt(savingsInstantTransitions.length); + for (long trans : savingsInstantTransitions) { + Ser.writeEpochSec(trans, out); + } + for (ZoneOffset offset : wallOffsets) { + Ser.writeOffset(offset, out); + } + out.writeByte(lastRules.length); + for (ZoneOffsetTransitionRule rule : lastRules) { + rule.writeExternal(out); + } + } + + /** + * Reads the state from the stream. + * + * @param in the input stream, not null + * @return the created object, not null + * @throws IOException if an error occurs + */ + static ZoneRules readExternal(DataInput in) throws IOException, ClassNotFoundException { + int stdSize = in.readInt(); + long[] stdTrans = (stdSize == 0) ? EMPTY_LONG_ARRAY + : new long[stdSize]; + for (int i = 0; i < stdSize; i++) { + stdTrans[i] = Ser.readEpochSec(in); + } + ZoneOffset[] stdOffsets = new ZoneOffset[stdSize + 1]; + for (int i = 0; i < stdOffsets.length; i++) { + stdOffsets[i] = Ser.readOffset(in); + } + int savSize = in.readInt(); + long[] savTrans = (savSize == 0) ? EMPTY_LONG_ARRAY + : new long[savSize]; + for (int i = 0; i < savSize; i++) { + savTrans[i] = Ser.readEpochSec(in); + } + ZoneOffset[] savOffsets = new ZoneOffset[savSize + 1]; + for (int i = 0; i < savOffsets.length; i++) { + savOffsets[i] = Ser.readOffset(in); + } + int ruleSize = in.readByte(); + ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ? + EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize]; + for (int i = 0; i < ruleSize; i++) { + rules[i] = ZoneOffsetTransitionRule.readExternal(in); + } + return new ZoneRules(stdTrans, stdOffsets, savTrans, savOffsets, rules); + } + + /** + * Checks of the zone rules are fixed, such that the offset never varies. + * + * @return true if the time-zone is fixed and the offset never changes + */ + public boolean isFixedOffset() { + return savingsInstantTransitions.length == 0; + } + + /** + * Gets the offset applicable at the specified instant in these rules. + *

    + * The mapping from an instant to an offset is simple, there is only + * one valid offset for each instant. + * This method returns that offset. + * + * @param instant the instant to find the offset for, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the offset, not null + */ + public ZoneOffset getOffset(Instant instant) { + if (savingsInstantTransitions.length == 0) { + return standardOffsets[0]; + } + long epochSec = instant.getEpochSecond(); + // check if using last rules + if (lastRules.length > 0 && + epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) { + int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]); + ZoneOffsetTransition[] transArray = findTransitionArray(year); + ZoneOffsetTransition trans = null; + for (int i = 0; i < transArray.length; i++) { + trans = transArray[i]; + if (epochSec < trans.toEpochSecond()) { + return trans.getOffsetBefore(); + } + } + return trans.getOffsetAfter(); + } + + // using historic rules + int index = Arrays.binarySearch(savingsInstantTransitions, epochSec); + if (index < 0) { + // switch negative insert position to start of matched range + index = -index - 2; + } + return wallOffsets[index + 1]; + } + + /** + * Gets a suitable offset for the specified local date-time in these rules. + *

    + * The mapping from a local date-time to an offset is not straightforward. + * There are three cases: + *

      + *
    • Normal, with one valid offset. For the vast majority of the year, the normal + * case applies, where there is a single valid offset for the local date-time.
    • + *
    • Gap, with zero valid offsets. This is when clocks jump forward typically + * due to the spring daylight savings change from "winter" to "summer". + * In a gap there are local date-time values with no valid offset.
    • + *
    • Overlap, with two valid offsets. This is when clocks are set back typically + * due to the autumn daylight savings change from "summer" to "winter". + * In an overlap there are local date-time values with two valid offsets.
    • + *

    + * Thus, for any given local date-time there can be zero, one or two valid offsets. + * This method returns the single offset in the Normal case, and in the Gap or Overlap + * case it returns the offset before the transition. + *

    + * Since, in the case of Gap and Overlap, the offset returned is a "best" value, rather + * than the "correct" value, it should be treated with care. Applications that care + * about the correct offset should use a combination of this method, + * {@link #getValidOffsets(LocalDateTime)} and {@link #getTransition(LocalDateTime)}. + * + * @param localDateTime the local date-time to query, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the best available offset for the local date-time, not null + */ + public ZoneOffset getOffset(LocalDateTime localDateTime) { + Object info = getOffsetInfo(localDateTime); + if (info instanceof ZoneOffsetTransition) { + return ((ZoneOffsetTransition) info).getOffsetBefore(); + } + return (ZoneOffset) info; + } + + /** + * Gets the offset applicable at the specified local date-time in these rules. + *

    + * The mapping from a local date-time to an offset is not straightforward. + * There are three cases: + *

      + *
    • Normal, with one valid offset. For the vast majority of the year, the normal + * case applies, where there is a single valid offset for the local date-time.
    • + *
    • Gap, with zero valid offsets. This is when clocks jump forward typically + * due to the spring daylight savings change from "winter" to "summer". + * In a gap there are local date-time values with no valid offset.
    • + *
    • Overlap, with two valid offsets. This is when clocks are set back typically + * due to the autumn daylight savings change from "summer" to "winter". + * In an overlap there are local date-time values with two valid offsets.
    • + *

    + * Thus, for any given local date-time there can be zero, one or two valid offsets. + * This method returns that list of valid offsets, which is a list of size 0, 1 or 2. + * In the case where there are two offsets, the earlier offset is returned at index 0 + * and the later offset at index 1. + *

    + * There are various ways to handle the conversion from a {@code LocalDateTime}. + * One technique, using this method, would be: + *

    +     *  List<ZoneOffset> validOffsets = rules.getOffset(localDT);
    +     *  if (validOffsets.size() == 1) {
    +     *    // Normal case: only one valid offset
    +     *    zoneOffset = validOffsets.get(0);
    +     *  } else {
    +     *    // Gap or Overlap: determine what to do from transition (which will be non-null)
    +     *    ZoneOffsetTransition trans = rules.getTransition(localDT);
    +     *  }
    +     * 
    + *

    + * In theory, it is possible for there to be more than two valid offsets. + * This would happen if clocks to be put back more than once in quick succession. + * This has never happened in the history of time-zones and thus has no special handling. + * However, if it were to happen, then the list would return more than 2 entries. + * + * @param localDateTime the local date-time to query for valid offsets, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the list of valid offsets, may be immutable, not null + */ + public List getValidOffsets(LocalDateTime localDateTime) { + // should probably be optimized + Object info = getOffsetInfo(localDateTime); + if (info instanceof ZoneOffsetTransition) { + return ((ZoneOffsetTransition) info).getValidOffsets(); + } + return Collections.singletonList((ZoneOffset) info); + } + + /** + * Gets the offset transition applicable at the specified local date-time in these rules. + *

    + * The mapping from a local date-time to an offset is not straightforward. + * There are three cases: + *

      + *
    • Normal, with one valid offset. For the vast majority of the year, the normal + * case applies, where there is a single valid offset for the local date-time.
    • + *
    • Gap, with zero valid offsets. This is when clocks jump forward typically + * due to the spring daylight savings change from "winter" to "summer". + * In a gap there are local date-time values with no valid offset.
    • + *
    • Overlap, with two valid offsets. This is when clocks are set back typically + * due to the autumn daylight savings change from "summer" to "winter". + * In an overlap there are local date-time values with two valid offsets.
    • + *

    + * A transition is used to model the cases of a Gap or Overlap. + * The Normal case will return null. + *

    + * There are various ways to handle the conversion from a {@code LocalDateTime}. + * One technique, using this method, would be: + *

    +     *  ZoneOffsetTransition trans = rules.getTransition(localDT);
    +     *  if (trans == null) {
    +     *    // Gap or Overlap: determine what to do from transition
    +     *  } else {
    +     *    // Normal case: only one valid offset
    +     *    zoneOffset = rule.getOffset(localDT);
    +     *  }
    +     * 
    + * + * @param localDateTime the local date-time to query for offset transition, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the offset transition, null if the local date-time is not in transition + */ + public ZoneOffsetTransition getTransition(LocalDateTime localDateTime) { + Object info = getOffsetInfo(localDateTime); + return (info instanceof ZoneOffsetTransition ? (ZoneOffsetTransition) info : null); + } + + private Object getOffsetInfo(LocalDateTime dt) { + if (savingsInstantTransitions.length == 0) { + return standardOffsets[0]; + } + // check if using last rules + if (lastRules.length > 0 && + dt.isAfter(savingsLocalTransitions[savingsLocalTransitions.length - 1])) { + ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear()); + Object info = null; + for (ZoneOffsetTransition trans : transArray) { + info = findOffsetInfo(dt, trans); + if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) { + return info; + } + } + return info; + } + + // using historic rules + int index = Arrays.binarySearch(savingsLocalTransitions, dt); + if (index == -1) { + // before first transition + return wallOffsets[0]; + } + if (index < 0) { + // switch negative insert position to start of matched range + index = -index - 2; + } else if (index < savingsLocalTransitions.length - 1 && + savingsLocalTransitions[index].equals(savingsLocalTransitions[index + 1])) { + // handle overlap immediately following gap + index++; + } + if ((index & 1) == 0) { + // gap or overlap + LocalDateTime dtBefore = savingsLocalTransitions[index]; + LocalDateTime dtAfter = savingsLocalTransitions[index + 1]; + ZoneOffset offsetBefore = wallOffsets[index / 2]; + ZoneOffset offsetAfter = wallOffsets[index / 2 + 1]; + if (offsetAfter.getTotalSeconds() > offsetBefore.getTotalSeconds()) { + // gap + return new ZoneOffsetTransition(dtBefore, offsetBefore, offsetAfter); + } else { + // overlap + return new ZoneOffsetTransition(dtAfter, offsetBefore, offsetAfter); + } + } else { + // normal (neither gap or overlap) + return wallOffsets[index / 2 + 1]; + } + } + + /** + * Finds the offset info for a local date-time and transition. + * + * @param dt the date-time, not null + * @param trans the transition, not null + * @return the offset info, not null + */ + private Object findOffsetInfo(LocalDateTime dt, ZoneOffsetTransition trans) { + LocalDateTime localTransition = trans.getDateTimeBefore(); + if (trans.isGap()) { + if (dt.isBefore(localTransition)) { + return trans.getOffsetBefore(); + } + if (dt.isBefore(trans.getDateTimeAfter())) { + return trans; + } else { + return trans.getOffsetAfter(); + } + } else { + if (dt.isBefore(localTransition) == false) { + return trans.getOffsetAfter(); + } + if (dt.isBefore(trans.getDateTimeAfter())) { + return trans.getOffsetBefore(); + } else { + return trans; + } + } + } + + /** + * Finds the appropriate transition array for the given year. + * + * @param year the year, not null + * @return the transition array, not null + */ + private ZoneOffsetTransition[] findTransitionArray(int year) { + Integer yearObj = year; // should use Year class, but this saves a class load + ZoneOffsetTransition[] transArray = lastRulesCache.get(yearObj); + if (transArray != null) { + return transArray; + } + ZoneOffsetTransitionRule[] ruleArray = lastRules; + transArray = new ZoneOffsetTransition[ruleArray.length]; + for (int i = 0; i < ruleArray.length; i++) { + transArray[i] = ruleArray[i].createTransition(year); + } + if (year < LAST_CACHED_YEAR) { + lastRulesCache.putIfAbsent(yearObj, transArray); + } + return transArray; + } + + /** + * Gets the standard offset for the specified instant in this zone. + *

    + * This provides access to historic information on how the standard offset + * has changed over time. + * The standard offset is the offset before any daylight saving time is applied. + * This is typically the offset applicable during winter. + * + * @param instant the instant to find the offset information for, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the standard offset, not null + */ + public ZoneOffset getStandardOffset(Instant instant) { + if (savingsInstantTransitions.length == 0) { + return standardOffsets[0]; + } + long epochSec = instant.getEpochSecond(); + 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]; + } + + /** + * Gets the amount of daylight savings in use for the specified instant in this zone. + *

    + * This provides access to historic information on how the amount of daylight + * savings has changed over time. + * This is the difference between the standard offset and the actual offset. + * Typically the amount is zero during winter and one hour during summer. + * Time-zones are second-based, so the nanosecond part of the duration will be zero. + *

    + * This default implementation calculates the duration from the + * {@link #getOffset(java.time.Instant) actual} and + * {@link #getStandardOffset(java.time.Instant) standard} offsets. + * + * @param instant the instant to find the daylight savings for, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the difference between the standard and actual offset, not null + */ + public Duration getDaylightSavings(Instant instant) { + if (savingsInstantTransitions.length == 0) { + return Duration.ZERO; + } + ZoneOffset standardOffset = getStandardOffset(instant); + ZoneOffset actualOffset = getOffset(instant); + return Duration.ofSeconds(actualOffset.getTotalSeconds() - standardOffset.getTotalSeconds()); + } + + /** + * Checks if the specified instant is in daylight savings. + *

    + * This checks if the standard offset and the actual offset are the same + * for the specified instant. + * If they are not, it is assumed that daylight savings is in operation. + *

    + * This default implementation compares the {@link #getOffset(java.time.Instant) actual} + * and {@link #getStandardOffset(java.time.Instant) standard} offsets. + * + * @param instant the instant to find the offset information for, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the standard offset, not null + */ + public boolean isDaylightSavings(Instant instant) { + return (getStandardOffset(instant).equals(getOffset(instant)) == false); + } + + /** + * Checks if the offset date-time is valid for these rules. + *

    + * To be valid, the local date-time must not be in a gap and the offset + * must match one of the valid offsets. + *

    + * This default implementation checks if {@link #getValidOffsets(java.time.LocalDateTime)} + * contains the specified offset. + * + * @param localDateTime the date-time to check, not null, but null + * may be ignored if the rules have a single offset for all instants + * @param offset the offset to check, null returns false + * @return true if the offset date-time is valid for these rules + */ + public boolean isValidOffset(LocalDateTime localDateTime, ZoneOffset offset) { + return getValidOffsets(localDateTime).contains(offset); + } + + /** + * Gets the next transition after the specified instant. + *

    + * This returns details of the next transition after the specified instant. + * For example, if the instant represents a point where "Summer" daylight savings time + * applies, then the method will return the transition to the next "Winter" time. + * + * @param instant the instant to get the next transition after, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the next transition after the specified instant, null if this is after the last transition + */ + public ZoneOffsetTransition nextTransition(Instant instant) { + if (savingsInstantTransitions.length == 0) { + return null; + } + long epochSec = instant.getEpochSecond(); + // check if using last rules + if (epochSec >= savingsInstantTransitions[savingsInstantTransitions.length - 1]) { + if (lastRules.length == 0) { + return null; + } + // search year the instant is in + int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]); + ZoneOffsetTransition[] transArray = findTransitionArray(year); + for (ZoneOffsetTransition trans : transArray) { + if (epochSec < trans.toEpochSecond()) { + return trans; + } + } + // use first from following year + if (year < Year.MAX_VALUE) { + transArray = findTransitionArray(year + 1); + return transArray[0]; + } + return null; + } + + // using historic rules + int index = Arrays.binarySearch(savingsInstantTransitions, epochSec); + if (index < 0) { + index = -index - 1; // switched value is the next transition + } else { + index += 1; // exact match, so need to add one to get the next + } + return new ZoneOffsetTransition(savingsInstantTransitions[index], wallOffsets[index], wallOffsets[index + 1]); + } + + /** + * Gets the previous transition before the specified instant. + *

    + * This returns details of the previous transition after the specified instant. + * For example, if the instant represents a point where "summer" daylight saving time + * applies, then the method will return the transition from the previous "winter" time. + * + * @param instant the instant to get the previous transition after, not null, but null + * may be ignored if the rules have a single offset for all instants + * @return the previous transition after the specified instant, null if this is before the first transition + */ + public ZoneOffsetTransition previousTransition(Instant instant) { + if (savingsInstantTransitions.length == 0) { + return null; + } + long epochSec = instant.getEpochSecond(); + if (instant.getNano() > 0 && epochSec < Long.MAX_VALUE) { + epochSec += 1; // allow rest of method to only use seconds + } + + // check if using last rules + long lastHistoric = savingsInstantTransitions[savingsInstantTransitions.length - 1]; + if (lastRules.length > 0 && epochSec > lastHistoric) { + // search year the instant is in + ZoneOffset lastHistoricOffset = wallOffsets[wallOffsets.length - 1]; + int year = findYear(epochSec, lastHistoricOffset); + ZoneOffsetTransition[] transArray = findTransitionArray(year); + for (int i = transArray.length - 1; i >= 0; i--) { + if (epochSec > transArray[i].toEpochSecond()) { + return transArray[i]; + } + } + // use last from preceeding year + int lastHistoricYear = findYear(lastHistoric, lastHistoricOffset); + if (--year > lastHistoricYear) { + transArray = findTransitionArray(year); + return transArray[transArray.length - 1]; + } + // drop through + } + + // using historic rules + int index = Arrays.binarySearch(savingsInstantTransitions, epochSec); + if (index < 0) { + index = -index - 1; + } + if (index <= 0) { + return null; + } + return new ZoneOffsetTransition(savingsInstantTransitions[index - 1], wallOffsets[index - 1], wallOffsets[index]); + } + + private int findYear(long epochSecond, ZoneOffset offset) { + // inline for performance + long localSecond = epochSecond + offset.getTotalSeconds(); + long localEpochDay = Math.floorDiv(localSecond, 86400); + return LocalDate.ofEpochDay(localEpochDay).getYear(); + } + + /** + * Gets the complete list of fully defined transitions. + *

    + * The complete set of transitions for this rules instance is defined by this method + * and {@link #getTransitionRules()}. This method returns those transitions that have + * been fully defined. These are typically historical, but may be in the future. + *

    + * The list will be empty for fixed offset rules and for any time-zone where there has + * only ever been a single offset. The list will also be empty if the transition rules are unknown. + * + * @return an immutable list of fully defined transitions, not null + */ + public List getTransitions() { + List list = new ArrayList<>(); + for (int i = 0; i < savingsInstantTransitions.length; i++) { + list.add(new ZoneOffsetTransition(savingsInstantTransitions[i], wallOffsets[i], wallOffsets[i + 1])); + } + return Collections.unmodifiableList(list); + } + + /** + * Gets the list of transition rules for years beyond those defined in the transition list. + *

    + * The complete set of transitions for this rules instance is defined by this method + * and {@link #getTransitions()}. This method returns instances of {@link ZoneOffsetTransitionRule} + * that define an algorithm for when transitions will occur. + *

    + * For any given {@code ZoneRules}, this list contains the transition rules for years + * beyond those years that have been fully defined. These rules typically refer to future + * daylight saving time rule changes. + *

    + * If the zone defines daylight savings into the future, then the list will normally + * be of size two and hold information about entering and exiting daylight savings. + * If the zone does not have daylight savings, or information about future changes + * is uncertain, then the list will be empty. + *

    + * The list will be empty for fixed offset rules and for any time-zone where there is no + * daylight saving time. The list will also be empty if the transition rules are unknown. + * + * @return an immutable list of transition rules, not null + */ + public List getTransitionRules() { + return Collections.unmodifiableList(Arrays.asList(lastRules)); + } + + /** + * Checks if this set of rules equals another. + *

    + * Two rule sets are equal if they will always result in the same output + * for any given input instant or local date-time. + * Rules from two different groups may return false even if they are in fact the same. + *

    + * This definition should result in implementations comparing their entire state. + * + * @param otherRules the other rules, null returns false + * @return true if this rules is the same as that specified + */ + @Override + public boolean equals(Object otherRules) { + if (this == otherRules) { + return true; + } + if (otherRules instanceof ZoneRules) { + ZoneRules other = (ZoneRules) otherRules; + return Arrays.equals(standardTransitions, other.standardTransitions) && + Arrays.equals(standardOffsets, other.standardOffsets) && + Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) && + Arrays.equals(wallOffsets, other.wallOffsets) && + Arrays.equals(lastRules, other.lastRules); + } + return false; + } + + /** + * Returns a suitable hash code given the definition of {@code #equals}. + * + * @return the hash code + */ + @Override + public int hashCode() { + return Arrays.hashCode(standardTransitions) ^ + Arrays.hashCode(standardOffsets) ^ + Arrays.hashCode(savingsInstantTransitions) ^ + Arrays.hashCode(wallOffsets) ^ + Arrays.hashCode(lastRules); + } + + /** + * Returns a string describing this object. + * + * @return a string for debugging, not null + */ + @Override + public String toString() { + return "ZoneRules[currentStandardOffset=" + standardOffsets[standardOffsets.length - 1] + "]"; + } + +} diff --git a/jdk/src/share/classes/java/time/zone/ZoneRulesException.java b/jdk/src/share/classes/java/time/zone/ZoneRulesException.java new file mode 100644 index 00000000000..e965af0dc34 --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/ZoneRulesException.java @@ -0,0 +1,98 @@ +/* + * 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 java.time.zone; + +import java.time.DateTimeException; + +/** + * Thrown to indicate a problem with time-zone configuration. + *

    + * This exception is used to indicate a problems with the configured + * time-zone rules. + * + *

    Specification for implementors

    + * This class is intended for use in a single thread. + * + * @since 1.8 + */ +public class ZoneRulesException extends DateTimeException { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -1632418723876261839L; + + /** + * Constructs a new date-time exception with the specified message. + * + * @param message the message to use for this exception, may be null + */ + public ZoneRulesException(String message) { + super(message); + } + + /** + * Constructs a new date-time exception with the specified message and cause. + * + * @param message the message to use for this exception, may be null + * @param cause the cause of the exception, may be null + */ + public ZoneRulesException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java b/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java new file mode 100644 index 00000000000..2c187a7e32e --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java @@ -0,0 +1,412 @@ +/* + * 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. + */ + +/* + * 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 java.time.zone; + +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.NavigableMap; +import java.util.Objects; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Provider of time-zone rules to the system. + *

    + * This class manages the configuration of time-zone rules. + * The static methods provide the public API that can be used to manage the providers. + * The abstract methods provide the SPI that allows rules to be provided. + *

    + * Rules are looked up primarily by zone ID, as used by {@link ZoneId}. + * Only zone region IDs may be used, zone offset IDs are not used here. + *

    + * Time-zone rules are political, thus the data can change at any time. + * Each provider will provide the latest rules for each zone ID, but they + * may also provide the history of how the rules changed. + * + *

    Specification for implementors

    + * This interface is a service provider that can be called by multiple threads. + * Implementations must be immutable and thread-safe. + *

    + * Providers must ensure that once a rule has been seen by the application, the + * rule must continue to be available. + *

    + * Many systems would like to update time-zone rules dynamically without stopping the JVM. + * When examined in detail, this is a complex problem. + * Providers may choose to handle dynamic updates, however the default provider does not. + * + * @since 1.8 + */ +public abstract class ZoneRulesProvider { + + /** + * The set of loaded providers. + */ + private static final CopyOnWriteArrayList PROVIDERS = new CopyOnWriteArrayList<>(); + /** + * The lookup from zone region ID to provider. + */ + private static final ConcurrentMap ZONES = new ConcurrentHashMap<>(512, 0.75f, 2); + static { + registerProvider(new TzdbZoneRulesProvider()); + ServiceLoader sl = ServiceLoader.load(ZoneRulesProvider.class, ClassLoader.getSystemClassLoader()); + List loaded = new ArrayList<>(); + Iterator it = sl.iterator(); + while (it.hasNext()) { + ZoneRulesProvider provider; + try { + provider = it.next(); + } catch (ServiceConfigurationError ex) { + if (ex.getCause() instanceof SecurityException) { + continue; // ignore the security exception, try the next provider + } + throw ex; + } + registerProvider0(provider); + } + // CopyOnWriteList could be slow if lots of providers and each added individually + PROVIDERS.addAll(loaded); + } + + //------------------------------------------------------------------------- + /** + * Gets the set of available zone IDs. + *

    + * These zone IDs are loaded and available for use by {@code ZoneId}. + * + * @return a modifiable copy of the set of zone IDs, not null + */ + public static Set getAvailableZoneIds() { + return new HashSet<>(ZONES.keySet()); + } + + /** + * Gets the rules for the zone ID. + *

    + * This returns the latest available rules for the zone ID. + *

    + * This method relies on time-zone data provider files that are configured. + * These are loaded using a {@code ServiceLoader}. + * + * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @return the rules for the ID, not null + * @throws ZoneRulesException if the zone ID is unknown + */ + public static ZoneRules getRules(String zoneId) { + Objects.requireNonNull(zoneId, "zoneId"); + return getProvider(zoneId).provideRules(zoneId); + } + + /** + * Gets the history of rules for the zone ID. + *

    + * Time-zones are defined by governments and change frequently. + * This method allows applications to find the history of changes to the + * rules for a single zone ID. The map is keyed by a string, which is the + * version string associated with the rules. + *

    + * The exact meaning and format of the version is provider specific. + * The version must follow lexicographical order, thus the returned map will + * be order from the oldest known rules to the newest available rules. + * The default 'TZDB' group uses version numbering consisting of the year + * followed by a letter, such as '2009e' or '2012f'. + *

    + * Implementations must provide a result for each valid zone ID, however + * they do not have to provide a history of rules. + * Thus the map will always contain one element, and will only contain more + * than one element if historical rule information is available. + * + * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @return a modifiable copy of the history of the rules for the ID, sorted + * from oldest to newest, not null + * @throws ZoneRulesException if the zone ID is unknown + */ + public static NavigableMap getVersions(String zoneId) { + Objects.requireNonNull(zoneId, "zoneId"); + return getProvider(zoneId).provideVersions(zoneId); + } + + /** + * Gets the provider for the zone ID. + * + * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @return the provider, not null + * @throws ZoneRulesException if the zone ID is unknown + */ + private static ZoneRulesProvider getProvider(String zoneId) { + ZoneRulesProvider provider = ZONES.get(zoneId); + if (provider == null) { + if (ZONES.isEmpty()) { + throw new ZoneRulesException("No time-zone data files registered"); + } + throw new ZoneRulesException("Unknown time-zone ID: " + zoneId); + } + return provider; + } + + //------------------------------------------------------------------------- + /** + * Registers a zone rules provider. + *

    + * This adds a new provider to those currently available. + * A provider supplies rules for one or more zone IDs. + * A provider cannot be registered if it supplies a zone ID that has already been + * registered. See the notes on time-zone IDs in {@link ZoneId}, especially + * the section on using the concept of a "group" to make IDs unique. + *

    + * To ensure the integrity of time-zones already created, there is no way + * to deregister providers. + * + * @param provider the provider to register, not null + * @throws ZoneRulesException if a region is already registered + */ + public static void registerProvider(ZoneRulesProvider provider) { + Objects.requireNonNull(provider, "provider"); + registerProvider0(provider); + PROVIDERS.add(provider); + } + + /** + * Registers the provider. + * + * @param provider the provider to register, not null + * @throws ZoneRulesException if unable to complete the registration + */ + private static void registerProvider0(ZoneRulesProvider provider) { + for (String zoneId : provider.provideZoneIds()) { + Objects.requireNonNull(zoneId, "zoneId"); + ZoneRulesProvider old = ZONES.putIfAbsent(zoneId, provider.provideBind(zoneId)); + if (old != null) { + throw new ZoneRulesException( + "Unable to register zone as one already registered with that ID: " + zoneId + + ", currently loading from provider: " + provider); + } + } + } + + //------------------------------------------------------------------------- + /** + * Refreshes the rules from the underlying data provider. + *

    + * This method is an extension point that allows providers to refresh their + * rules dynamically at a time of the applications choosing. + * After calling this method, the offset stored in any {@link ZonedDateTime} + * may be invalid for the zone ID. + *

    + * Dynamic behavior is entirely optional and most providers, including the + * default provider, do not support it. + * + * @return true if the rules were updated + * @throws ZoneRulesException if an error occurs during the refresh + */ + public static boolean refresh() { + boolean changed = false; + for (ZoneRulesProvider provider : PROVIDERS) { + changed |= provider.provideRefresh(); + } + return changed; + } + + //----------------------------------------------------------------------- + /** + * Constructor. + */ + protected ZoneRulesProvider() { + } + + //----------------------------------------------------------------------- + /** + * SPI method to get the available zone IDs. + *

    + * This obtains the IDs that this {@code ZoneRulesProvider} provides. + * A provider should provide data for at least one region. + *

    + * The returned regions remain available and valid for the lifetime of the application. + * A dynamic provider may increase the set of regions as more data becomes available. + * + * @return the unmodifiable set of region IDs being provided, not null + */ + protected abstract Set provideZoneIds(); + + /** + * SPI method to bind to the specified zone ID. + *

    + * {@code ZoneRulesProvider} has a lookup from zone ID to provider. + * This method is used when building that lookup, allowing providers + * to insert a derived provider that is precisely tuned to the zone ID. + * This replaces two hash map lookups by one, enhancing performance. + *

    + * This optimization is optional. Returning {@code this} is acceptable. + *

    + * This implementation creates a bound provider that caches the + * rules from the underlying provider. The request to version history + * is forward on to the underlying. This is suitable for providers that + * cannot change their contents during the lifetime of the JVM. + * + * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @return the resolved provider for the ID, not null + * @throws DateTimeException if there is no provider for the specified group + */ + protected ZoneRulesProvider provideBind(String zoneId) { + return new BoundProvider(this, zoneId); + } + + /** + * SPI method to get the rules for the zone ID. + *

    + * This loads the rules for the region and version specified. + * The version may be null to indicate the "latest" version. + * + * @param regionId the time-zone region ID, not null + * @return the rules, not null + * @throws DateTimeException if rules cannot be obtained + */ + protected abstract ZoneRules provideRules(String regionId); + + /** + * SPI method to get the history of rules for the zone ID. + *

    + * This returns a map of historical rules keyed by a version string. + * The exact meaning and format of the version is provider specific. + * The version must follow lexicographical order, thus the returned map will + * be order from the oldest known rules to the newest available rules. + * The default 'TZDB' group uses version numbering consisting of the year + * followed by a letter, such as '2009e' or '2012f'. + *

    + * Implementations must provide a result for each valid zone ID, however + * they do not have to provide a history of rules. + * Thus the map will always contain one element, and will only contain more + * than one element if historical rule information is available. + *

    + * The returned versions remain available and valid for the lifetime of the application. + * A dynamic provider may increase the set of versions as more data becomes available. + * + * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @return a modifiable copy of the history of the rules for the ID, sorted + * from oldest to newest, not null + * @throws ZoneRulesException if the zone ID is unknown + */ + protected abstract NavigableMap provideVersions(String zoneId); + + /** + * SPI method to refresh the rules from the underlying data provider. + *

    + * This method provides the opportunity for a provider to dynamically + * recheck the underlying data provider to find the latest rules. + * This could be used to load new rules without stopping the JVM. + * Dynamic behavior is entirely optional and most providers do not support it. + *

    + * This implementation returns false. + * + * @return true if the rules were updated + * @throws DateTimeException if an error occurs during the refresh + */ + protected boolean provideRefresh() { + return false; + } + + //------------------------------------------------------------------------- + /** + * A provider bound to a single zone ID. + */ + private static class BoundProvider extends ZoneRulesProvider { + private final ZoneRulesProvider provider; + private final String zoneId; + private final ZoneRules rules; + + private BoundProvider(ZoneRulesProvider provider, String zoneId) { + this.provider = provider; + this.zoneId = zoneId; + this.rules = provider.provideRules(zoneId); + } + + @Override + protected Set provideZoneIds() { + return new HashSet<>(Collections.singleton(zoneId)); + } + + @Override + protected ZoneRules provideRules(String regionId) { + return rules; + } + + @Override + protected NavigableMap provideVersions(String zoneId) { + return provider.provideVersions(zoneId); + } + + @Override + public String toString() { + return zoneId; + } + } + +} diff --git a/jdk/src/share/classes/java/time/zone/package-info.java b/jdk/src/share/classes/java/time/zone/package-info.java new file mode 100644 index 00000000000..f50b3de2f5d --- /dev/null +++ b/jdk/src/share/classes/java/time/zone/package-info.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* + * 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. + */ + +/** + *

    + * Support for time-zones and their rules. + *

    + *

    + * Daylight Saving Time and Time-Zones are concepts used by Governments to alter local time. + * This package provides support for time-zones, their rules and the resulting + * gaps and overlaps in the local time-line typically caused by Daylight Saving Time. + *

    + * + *

    Package specification

    + *

    + * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface + * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown. + * The Javadoc "@param" definition is used to summarise the null-behavior. + * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method. + *

    + *

    + * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException} + * or a {@link java.time.DateTimeException}. + *

    + * @since JDK1.8 + */ +package java.time.zone; diff --git a/jdk/src/share/classes/java/util/Calendar.java b/jdk/src/share/classes/java/util/Calendar.java index fdb4cf73ecb..600da93ee52 100644 --- a/jdk/src/share/classes/java/util/Calendar.java +++ b/jdk/src/share/classes/java/util/Calendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -151,9 +151,9 @@ import sun.util.locale.provider.CalendarDataUtility; * calendar field values to determine the date and time in the * following way. * - *

    If there is any conflict in calendar field values, + *

    If there is any conflict in calendar field values, * Calendar gives priorities to calendar fields that have been set - * more recently. The following are the default combinations of the + * more recently. The following are the default combinations of the * calendar fields. The most recent combination, as determined by the * most recently set single field, will be used. * @@ -1019,6 +1019,556 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableThere are two ways to set a {@code Calendar} to a date-time value. One + * is to set the instant parameter to a millisecond offset from the Epoch. The other is to set individual + * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired + * values. These two ways can't be mixed. Trying to set both the instant and + * individual fields will cause an {@link IllegalStateException} to be + * thrown. However, it is permitted to override previous values of the + * instant or field parameters. + * + *

    If no enough field parameters are given for determining date and/or + * time, calendar specific default values are used when building a + * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value + * isn't given for the Gregorian calendar, 1970 will be used. If there are + * any conflicts among field parameters, the resolution rules are applied. + * Therefore, the order of field setting matters. + * + *

    In addition to the date-time parameters, + * the {@linkplain #setLocale(Locale) locale}, + * {@linkplain #setTimeZone(TimeZone) time zone}, + * {@linkplain #setWeekDefinition(int, int) week definition}, and + * {@linkplain #setLenient(boolean) leniency mode} parameters can be set. + * + *

    Examples + *

    The following are sample usages. Sample code assumes that the + * {@code Calendar} constants are statically imported. + * + *

    The following code produces a {@code Calendar} with date 2012-12-31 + * (Gregorian) because Monday is the first day of a week with the ISO 8601 + * compatible week parameters. + *

    +     *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
    +     *                        .setWeekDate(2013, 1, MONDAY).build();
    + *

    The following code produces a Japanese {@code Calendar} with date + * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA} + * is Heisei that started on that day. + *

    +     *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
    +     *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();
    + * + * @since 1.8 + * @see Calendar#getInstance(TimeZone, Locale) + * @see Calendar#fields + */ + public static class Builder { + private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR + private static final int WEEK_YEAR = FIELD_COUNT; + + private long instant; + // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined + private int[] fields; + // Pseudo timestamp starting from MINIMUM_USER_STAMP. + // (COMPUTED is used to indicate that the instant has been set.) + private int nextStamp; + // maxFieldIndex keeps the max index of fields which have been set. + // (WEEK_YEAR is never included.) + private int maxFieldIndex; + private String type; + private TimeZone zone; + private boolean lenient = true; + private Locale locale; + private int firstDayOfWeek, minimalDaysInFirstWeek; + + /** + * Constructs a {@code Calendar.Builder}. + */ + public Builder() { + } + + /** + * Sets the instant parameter to the given {@code instant} value that is + * a millisecond offset from the + * Epoch. + * + * @param instant a millisecond offset from the Epoch + * @return this {@code Calendar.Builder} + * @throws IllegalStateException if any of the field parameters have + * already been set + * @see Calendar#setTime(Date) + * @see Calendar#setTimeInMillis(long) + * @see Calendar#time + */ + public Builder setInstant(long instant) { + if (fields != null) { + throw new IllegalStateException(); + } + this.instant = instant; + nextStamp = COMPUTED; + return this; + } + + /** + * Sets the instant parameter to the {@code instant} value given by a + * {@link Date}. This method is equivalent to a call to + * {@link #setInstant(long) setInstant(instant.getTime())}. + * + * @param instant a {@code Date} representing a millisecond offset from + * the Epoch + * @return this {@code Calendar.Builder} + * @throws NullPointerException if {@code instant} is {@code null} + * @throws IllegalStateException if any of the field parameters have + * already been set + * @see Calendar#setTime(Date) + * @see Calendar#setTimeInMillis(long) + * @see Calendar#time + */ + public Builder setInstant(Date instant) { + return setInstant(instant.getTime()); // NPE if instant == null + } + + /** + * Sets the {@code field} parameter to the given {@code value}. + * {@code field} is an index to the {@link Calendar#fields}, such as + * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is + * not performed in this method. Any out of range values are either + * normalized in lenient mode or detected as an invalid value in + * non-lenient mode when building a {@code Calendar}. + * + * @param field an index to the {@code Calendar} fields + * @param value the field value + * @return this {@code Calendar.Builder} + * @throws IllegalArgumentException if {@code field} is invalid + * @throws IllegalStateException if the instant value has already been set, + * or if fields have been set too many + * (approximately {@link Integer#MAX_VALUE}) times. + * @see Calendar#set(int, int) + */ + public Builder set(int field, int value) { + // Note: WEEK_YEAR can't be set with this method. + if (field < 0 || field >= FIELD_COUNT) { + throw new IllegalArgumentException("field is invalid"); + } + if (isInstantSet()) { + throw new IllegalStateException("instant has been set"); + } + allocateFields(); + internalSet(field, value); + return this; + } + + /** + * Sets field parameters to their values given by + * {@code fieldValuePairs} that are pairs of a field and its value. + * For example, + *
    +         *   setFeilds(Calendar.YEAR, 2013,
    +         *             Calendar.MONTH, Calendar.DECEMBER,
    +         *             Calendar.DAY_OF_MONTH, 23);
    + * is equivalent to the sequence of the following + * {@link #set(int, int) set} calls: + *
    +         *   set(Calendar.YEAR, 2013)
    +         *   .set(Calendar.MONTH, Calendar.DECEMBER)
    +         *   .set(Calendar.DAY_OF_MONTH, 23);
    + * + * @param fieldValuePairs field-value pairs + * @return this {@code Calendar.Builder} + * @throws NullPointerException if {@code fieldValuePairs} is {@code null} + * @throws IllegalArgumentException if any of fields are invalid, + * or if {@code fieldValuePairs.length} is an odd number. + * @throws IllegalStateException if the instant value has been set, + * or if fields have been set too many (approximately + * {@link Integer#MAX_VALUE}) times. + */ + public Builder setFields(int... fieldValuePairs) { + int len = fieldValuePairs.length; + if ((len % 2) != 0) { + throw new IllegalArgumentException(); + } + if (isInstantSet()) { + throw new IllegalStateException("instant has been set"); + } + if ((nextStamp + len / 2) < 0) { + throw new IllegalStateException("stamp counter overflow"); + } + allocateFields(); + for (int i = 0; i < len; ) { + int field = fieldValuePairs[i++]; + // Note: WEEK_YEAR can't be set with this method. + if (field < 0 || field >= FIELD_COUNT) { + throw new IllegalArgumentException("field is invalid"); + } + internalSet(field, fieldValuePairs[i++]); + } + return this; + } + + /** + * Sets the date field parameters to the values given by {@code year}, + * {@code month}, and {@code dayOfMonth}. This method is equivalent to + * a call to: + *
    +         *   setFields(Calendar.YEAR, year,
    +         *             Calendar.MONTH, month,
    +         *             Calendar.DAY_OF_MONTH, dayOfMonth);
    + * + * @param year the {@link Calendar#YEAR YEAR} value + * @param month the {@link Calendar#MONTH MONTH} value + * (the month numbering is 0-based). + * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value + * @return this {@code Calendar.Builder} + */ + public Builder setDate(int year, int month, int dayOfMonth) { + return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth); + } + + /** + * Sets the time of day field parameters to the values given by + * {@code hourOfDay}, {@code minute}, and {@code second}. This method is + * equivalent to a call to: + *
    +         *   setTimeOfDay(hourOfDay, minute, second, 0);
    + * + * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value + * (24-hour clock) + * @param minute the {@link Calendar#MINUTE MINUTE} value + * @param second the {@link Calendar#SECOND SECOND} value + * @return this {@code Calendar.Builder} + */ + public Builder setTimeOfDay(int hourOfDay, int minute, int second) { + return setTimeOfDay(hourOfDay, minute, second, 0); + } + + /** + * Sets the time of day field parameters to the values given by + * {@code hourOfDay}, {@code minute}, {@code second}, and + * {@code millis}. This method is equivalent to a call to: + *
    +         *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
    +         *             Calendar.MINUTE, minute,
    +         *             Calendar.SECOND, second,
    +         *             Calendar.MILLISECOND, millis);
    + * + * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value + * (24-hour clock) + * @param minute the {@link Calendar#MINUTE MINUTE} value + * @param second the {@link Calendar#SECOND SECOND} value + * @param millis the {@link Calendar#MILLISECOND MILLISECOND} value + * @return this {@code Calendar.Builder} + */ + public Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) { + return setFields(HOUR_OF_DAY, hourOfDay, MINUTE, minute, + SECOND, second, MILLISECOND, millis); + } + + /** + * Sets the week-based date parameters to the values with the given + * date specifiers - week year, week of year, and day of week. + * + *

    If the specified calendar doesn't support week dates, the + * {@link #build() build} method will throw an {@link IllegalArgumentException}. + * + * @param weekYear the week year + * @param weekOfYear the week number based on {@code weekYear} + * @param dayOfWeek the day of week value: one of the constants + * for the {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} field: + * {@link Calendar#SUNDAY SUNDAY}, ..., {@link Calendar#SATURDAY SATURDAY}. + * @return this {@code Calendar.Builder} + * @see Calendar#setWeekDate(int, int, int) + * @see Calendar#isWeekDateSupported() + */ + public Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { + allocateFields(); + internalSet(WEEK_YEAR, weekYear); + internalSet(WEEK_OF_YEAR, weekOfYear); + internalSet(DAY_OF_WEEK, dayOfWeek); + return this; + } + + /** + * Sets the time zone parameter to the given {@code zone}. If no time + * zone parameter is given to this {@code Caledar.Builder}, the + * {@linkplain TimeZone#getDefault() default + * TimeZone} will be used in the {@link #build() build} + * method. + * + * @param zone the {@link TimeZone} + * @return this {@code Calendar.Builder} + * @throws NullPointerException if {@code zone} is {@code null} + * @see Calendar#setTimeZone(TimeZone) + */ + public Builder setTimeZone(TimeZone zone) { + if (zone == null) { + throw new NullPointerException(); + } + this.zone = zone; + return this; + } + + /** + * Sets the lenient mode parameter to the value given by {@code lenient}. + * If no lenient parameter is given to this {@code Calendar.Builder}, + * lenient mode will be used in the {@link #build() build} method. + * + * @param lenient {@code true} for lenient mode; + * {@code false} for non-lenient mode + * @return this {@code Calendar.Builder} + * @see Calendar#setLenient(boolean) + */ + public Builder setLenient(boolean lenient) { + this.lenient = lenient; + return this; + } + + /** + * Sets the calendar type parameter to the given {@code type}. The + * calendar type given by this method has precedence over any explicit + * or implicit calendar type given by the + * {@linkplain #setLocale(Locale) locale}. + * + *

    In addition to the available calendar types returned by the + * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes} + * method, {@code "gregorian"} and {@code "iso8601"} as aliases of + * {@code "gregory"} can be used with this method. + * + * @param type the calendar type + * @return this {@code Calendar.Builder} + * @throws NullPointerException if {@code type} is {@code null} + * @throws IllegalArgumentException if {@code type} is unknown + * @throws IllegalStateException if another calendar type has already been set + * @see Calendar#getCalendarType() + * @see Calendar#getAvailableCalendarTypes() + */ + public Builder setCalendarType(String type) { + if (type.equals("gregorian")) { // NPE if type == null + type = "gregory"; + } + if (!Calendar.getAvailableCalendarTypes().contains(type) + && !type.equals("iso8601")) { + throw new IllegalArgumentException("unknown calendar type: " + type); + } + if (this.type == null) { + this.type = type; + } else { + if (!this.type.equals(type)) { + throw new IllegalStateException("calendar type override"); + } + } + return this; + } + + /** + * Sets the locale parameter to the given {@code locale}. If no locale + * is given to this {@code Calendar.Builder}, the {@linkplain + * Locale#getDefault(Locale.Category) default Locale} + * for {@link Locale.Category#FORMAT} will be used. + * + *

    If no calendar type is explicitly given by a call to the + * {@link #setCalendarType(String) setCalendarType} method, + * the {@code Locale} value is used to determine what type of + * {@code Calendar} to be built. + * + *

    If no week definition parameters are explicitly given by a call to + * the {@link #setWeekDefinition(int,int) setWeekDefinition} method, the + * {@code Locale}'s default values are used. + * + * @param locale the {@link Locale} + * @throws NullPointerException if {@code locale} is {@code null} + * @return this {@code Calendar.Builder} + * @see Calendar#getInstance(Locale) + */ + public Builder setLocale(Locale locale) { + if (locale == null) { + throw new NullPointerException(); + } + this.locale = locale; + return this; + } + + /** + * Sets the week definition parameters to the values given by + * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are + * used to determine the first + * week of a year. The parameters given by this method have + * precedence over the default values given by the + * {@linkplain #setLocale(Locale) locale}. + * + * @param firstDayOfWeek the first day of a week; one of + * {@link Calendar#SUNDAY} to {@link Calendar#SATURDAY} + * @param minimalDaysInFirstWeek the minimal number of days in the first + * week (1..7) + * @return this {@code Calendar.Builder} + * @throws IllegalArgumentException if {@code firstDayOfWeek} or + * {@code minimalDaysInFirstWeek} is invalid + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + */ + public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) { + if (!isValidWeekParameter(firstDayOfWeek) + || !isValidWeekParameter(minimalDaysInFirstWeek)) { + throw new IllegalArgumentException(); + } + this.firstDayOfWeek = firstDayOfWeek; + this.minimalDaysInFirstWeek = minimalDaysInFirstWeek; + return this; + } + + /** + * Returns a {@code Calendar} built from the parameters set by the + * setter methods. The calendar type given by the {@link #setCalendarType(String) + * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is + * used to determine what {@code Calendar} to be created. If no explicit + * calendar type is given, the locale's default calendar is created. + * + *

    If the calendar type is {@code "iso8601"}, the + * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date} + * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)} + * to be the proleptic Gregorian calendar. Its week definition + * parameters are also set to be compatible + * with the ISO 8601 standard. Note that the + * {@link GregorianCalendar#getCalendarType() getCalendarType} method of + * a {@code GregorianCalendar} created with {@code "iso8601"} returns + * {@code "gregory"}. + * + *

    The default values are used for locale and time zone if these + * parameters haven't been given explicitly. + * + *

    Any out of range field values are either normalized in lenient + * mode or detected as an invalid value in non-lenient mode. + * + * @return a {@code Calendar} built with parameters of this {@code + * Calendar.Builder} + * @throws IllegalArgumentException if the calendar type is unknown, or + * if any invalid field values are given in non-lenient mode, or + * if a week date is given for the calendar type that doesn't + * support week dates. + * @see Calendar#getInstance(TimeZone, Locale) + * @see Locale#getDefault(Locale.Category) + * @see TimeZone#getDefault() + */ + public Calendar build() { + if (locale == null) { + locale = Locale.getDefault(); + } + if (zone == null) { + zone = TimeZone.getDefault(); + } + Calendar cal; + if (type == null) { + type = locale.getUnicodeLocaleType("ca"); + } + if (type == null) { + if (locale.getCountry() == "TH" + && locale.getLanguage() == "th") { + type = "buddhist"; + } else { + type = "gregory"; + } + } + switch (type) { + case "gregory": + cal = new GregorianCalendar(zone, locale, true); + break; + case "iso8601": + GregorianCalendar gcal = new GregorianCalendar(zone, locale, true); + // make gcal a proleptic Gregorian + gcal.setGregorianChange(new Date(Long.MIN_VALUE)); + // and week definition to be compatible with ISO 8601 + setWeekDefinition(MONDAY, 4); + cal = gcal; + break; + case "buddhist": + cal = new BuddhistCalendar(zone, locale); + cal.clear(); + break; + case "japanese": + cal = new JapaneseImperialCalendar(zone, locale, true); + break; + default: + throw new IllegalArgumentException("unknown calendar type: " + type); + } + cal.setLenient(lenient); + if (firstDayOfWeek != 0) { + cal.setFirstDayOfWeek(firstDayOfWeek); + cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek); + } + if (isInstantSet()) { + cal.setTimeInMillis(instant); + cal.complete(); + return cal; + } + + if (fields != null) { + boolean weekDate = isSet(WEEK_YEAR) + && fields[WEEK_YEAR] > fields[YEAR]; + if (weekDate && !cal.isWeekDateSupported()) { + throw new IllegalArgumentException("week date is unsupported by " + type); + } + + // Set the fields from the min stamp to the max stamp so that + // the fields resolution works in the Calendar. + for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) { + for (int index = 0; index <= maxFieldIndex; index++) { + if (fields[index] == stamp) { + cal.set(index, fields[NFIELDS + index]); + break; + } + } + } + + if (weekDate) { + int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1; + int dayOfWeek = isSet(DAY_OF_WEEK) + ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek(); + cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek); + } + cal.complete(); + } + + return cal; + } + + private void allocateFields() { + if (fields == null) { + fields = new int[NFIELDS * 2]; + nextStamp = MINIMUM_USER_STAMP; + maxFieldIndex = -1; + } + } + + private void internalSet(int field, int value) { + fields[field] = nextStamp++; + if (nextStamp < 0) { + throw new IllegalStateException("stamp counter overflow"); + } + fields[NFIELDS + field] = value; + if (field > maxFieldIndex && field < WEEK_YEAR) { + maxFieldIndex = field; + } + } + + private boolean isInstantSet() { + return nextStamp == COMPUTED; + } + + private boolean isSet(int index) { + return fields != null && fields[index] > UNSET; + } + + private boolean isValidWeekParameter(int value) { + return value > 0 && value <= 7; + } + } + /** * Constructs a Calendar with the default time zone * and locale. @@ -1109,7 +1659,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable stamp_b) ? stamp_a : stamp_b; } + /** + * Returns an unmodifiable {@code Set} containing all calendar types + * supported by {@code Calendar} in the runtime environment. The available + * calendar types can be used for the Unicode locale extensions. + * The {@code Set} returned contains at least {@code "gregory"}. The + * calendar types don't include aliases, such as {@code "gregorian"} for + * {@code "gregory"}. + * + * @return an unmodifiable {@code Set} containing all available calendar types + * @since 1.8 + * @see #getCalendarType() + * @see Calendar.Builder#setCalendarType(String) + * @see Locale#getUnicodeLocaleType(String) + */ + public static Set getAvailableCalendarTypes() { + return AvailableCalendarTypes.SET; + } + + private static class AvailableCalendarTypes { + private static final Set SET; + static { + Set set = new HashSet<>(3); + set.add("gregory"); + set.add("buddhist"); + set.add("japanese"); + SET = Collections.unmodifiableSet(set); + } + private AvailableCalendarTypes() { + } + } + /** * Returns the calendar type of this {@code Calendar}. Calendar types are * defined by the Unicode Locale Data Markup Language (LDML) diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index 59056d0d1be..f5f479588c1 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -50,6 +50,21 @@ import java.text.NumberFormat; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.Queries; +import java.time.temporal.OffsetDate; +import java.time.temporal.OffsetDateTime; +import java.time.temporal.OffsetTime; +import java.time.temporal.ChronoZonedDateTime; +import java.time.format.TextStyle; +import java.time.zone.ZoneRules; + import sun.misc.DoubleConsts; import sun.misc.FormattedFloatingDecimal; @@ -254,8 +269,8 @@ import sun.misc.FormattedFloatingDecimal; * * *

  • Date/Time - may be applied to Java types which are capable of - * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, and - * {@link Date}. + * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, + * {@link Date} and {@link TemporalAccessor TemporalAccessor} * *
  • Percent - produces a literal {@code '%'} * ('\u0025') @@ -1488,7 +1503,7 @@ import sun.misc.FormattedFloatingDecimal; *

    Date/Time

    * *

    This conversion may be applied to {@code long}, {@link Long}, {@link - * Calendar}, and {@link Date}. + * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor} * * * @@ -2782,6 +2797,9 @@ public final class Formatter implements Closeable, Flushable { } else if (arg instanceof Calendar) { cal = (Calendar) ((Calendar)arg).clone(); cal.setLenient(true); + } else if (arg instanceof TemporalAccessor) { + print((TemporalAccessor)arg, c, l); + return; } else { failConversion(c, arg); } @@ -3827,7 +3845,6 @@ public final class Formatter implements Closeable, Flushable { Locale l) throws IOException { - assert(width == -1); if (sb == null) sb = new StringBuilder(); switch (c) { @@ -4033,6 +4050,242 @@ public final class Formatter implements Closeable, Flushable { return sb; } + private void print(TemporalAccessor t, char c, Locale l) throws IOException { + StringBuilder sb = new StringBuilder(); + print(sb, t, c, l); + // justify based on width + String s = justify(sb.toString()); + if (f.contains(Flags.UPPERCASE)) + s = s.toUpperCase(); + a.append(s); + } + + private Appendable print(StringBuilder sb, TemporalAccessor t, char c, + Locale l) throws IOException { + if (sb == null) + sb = new StringBuilder(); + try { + switch (c) { + case DateTime.HOUR_OF_DAY_0: { // 'H' (00 - 23) + int i = t.get(ChronoField.HOUR_OF_DAY); + sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + break; + } + case DateTime.HOUR_OF_DAY: { // 'k' (0 - 23) -- like H + int i = t.get(ChronoField.HOUR_OF_DAY); + sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + break; + } + case DateTime.HOUR_0: { // 'I' (01 - 12) + int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); + sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + break; + } + case DateTime.HOUR: { // 'l' (1 - 12) -- like I + int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); + sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + break; + } + case DateTime.MINUTE: { // 'M' (00 - 59) + int i = t.get(ChronoField.MINUTE_OF_HOUR); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 2, l)); + break; + } + case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) + int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 9, l)); + break; + } + case DateTime.MILLISECOND: { // 'L' (000 - 999) + int i = t.get(ChronoField.MILLI_OF_SECOND); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 3, l)); + break; + } + case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) + long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L + + t.getLong(ChronoField.MILLI_OF_SECOND); + Flags flags = Flags.NONE; + sb.append(localizedMagnitude(null, i, flags, width, l)); + break; + } + case DateTime.AM_PM: { // 'p' (am or pm) + // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper + String[] ampm = { "AM", "PM" }; + if (l != null && l != Locale.US) { + DateFormatSymbols dfs = DateFormatSymbols.getInstance(l); + ampm = dfs.getAmPmStrings(); + } + String s = ampm[t.get(ChronoField.AMPM_OF_DAY)]; + sb.append(s.toLowerCase(l != null ? l : Locale.US)); + break; + } + case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) + long i = t.getLong(ChronoField.INSTANT_SECONDS); + Flags flags = Flags.NONE; + sb.append(localizedMagnitude(null, i, flags, width, l)); + break; + } + case DateTime.SECOND: { // 'S' (00 - 60 - leap second) + int i = t.get(ChronoField.SECOND_OF_MINUTE); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 2, l)); + break; + } + case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? + int i = t.get(ChronoField.OFFSET_SECONDS); + boolean neg = i < 0; + sb.append(neg ? '-' : '+'); + if (neg) + i = -i; + int min = i / 60; + // combine minute and hour into a single integer + int offset = (min / 60) * 100 + (min % 60); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, offset, flags, 4, l)); + break; + } + case DateTime.ZONE: { // 'Z' (symbol) + ZoneId zid = t.query(Queries.zone()); + if (zid == null) { + throw new IllegalFormatConversionException(c, t.getClass()); + } + if (!(zid instanceof ZoneOffset) && + t.isSupported(ChronoField.INSTANT_SECONDS)) { + Instant instant = Instant.from(t); + sb.append(TimeZone.getTimeZone(zid.getId()) + .getDisplayName(zid.getRules().isDaylightSavings(instant), + TimeZone.SHORT, + (l == null) ? Locale.US : l)); + break; + } + sb.append(zid.getId()); + break; + } + // Date + case DateTime.NAME_OF_DAY_ABBREV: // 'a' + case DateTime.NAME_OF_DAY: { // 'A' + int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1; + Locale lt = ((l == null) ? Locale.US : l); + DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); + if (c == DateTime.NAME_OF_DAY) + sb.append(dfs.getWeekdays()[i]); + else + sb.append(dfs.getShortWeekdays()[i]); + break; + } + case DateTime.NAME_OF_MONTH_ABBREV: // 'b' + case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b + case DateTime.NAME_OF_MONTH: { // 'B' + int i = t.get(ChronoField.MONTH_OF_YEAR) - 1; + Locale lt = ((l == null) ? Locale.US : l); + DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); + if (c == DateTime.NAME_OF_MONTH) + sb.append(dfs.getMonths()[i]); + else + sb.append(dfs.getShortMonths()[i]); + break; + } + case DateTime.CENTURY: // 'C' (00 - 99) + case DateTime.YEAR_2: // 'y' (00 - 99) + case DateTime.YEAR_4: { // 'Y' (0000 - 9999) + int i = t.get(ChronoField.YEAR); + int size = 2; + switch (c) { + case DateTime.CENTURY: + i /= 100; + break; + case DateTime.YEAR_2: + i %= 100; + break; + case DateTime.YEAR_4: + size = 4; + break; + } + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, size, l)); + break; + } + case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) + case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d + int i = t.get(ChronoField.DAY_OF_MONTH); + Flags flags = (c == DateTime.DAY_OF_MONTH_0 + ? Flags.ZERO_PAD + : Flags.NONE); + sb.append(localizedMagnitude(null, i, flags, 2, l)); + break; + } + case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) + int i = t.get(ChronoField.DAY_OF_YEAR); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 3, l)); + break; + } + case DateTime.MONTH: { // 'm' (01 - 12) + int i = t.get(ChronoField.MONTH_OF_YEAR); + Flags flags = Flags.ZERO_PAD; + sb.append(localizedMagnitude(null, i, flags, 2, l)); + break; + } + + // Composites + case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) + case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) + char sep = ':'; + print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); + print(sb, t, DateTime.MINUTE, l); + if (c == DateTime.TIME) { + sb.append(sep); + print(sb, t, DateTime.SECOND, l); + } + break; + } + case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) + char sep = ':'; + print(sb, t, DateTime.HOUR_0, l).append(sep); + print(sb, t, DateTime.MINUTE, l).append(sep); + print(sb, t, DateTime.SECOND, l).append(' '); + // this may be in wrong place for some locales + StringBuilder tsb = new StringBuilder(); + print(tsb, t, DateTime.AM_PM, l); + sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US)); + break; + } + case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) + char sep = ' '; + print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); + print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); + print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(sb, t, DateTime.TIME, l).append(sep); + print(sb, t, DateTime.ZONE, l).append(sep); + print(sb, t, DateTime.YEAR_4, l); + break; + } + case DateTime.DATE: { // 'D' (mm/dd/yy) + char sep = '/'; + print(sb, t, DateTime.MONTH, l).append(sep); + print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(sb, t, DateTime.YEAR_2, l); + break; + } + case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) + char sep = '-'; + print(sb, t, DateTime.YEAR_4, l).append(sep); + print(sb, t, DateTime.MONTH, l).append(sep); + print(sb, t, DateTime.DAY_OF_MONTH_0, l); + break; + } + default: + assert false; + } + } catch (DateTimeException x) { + throw new IllegalFormatConversionException(c, t.getClass()); + } + return sb; + } + // -- Methods to support throwing exceptions -- private void failMismatch(Flags f, char c) { diff --git a/jdk/src/share/classes/java/util/GregorianCalendar.java b/jdk/src/share/classes/java/util/GregorianCalendar.java index c171fd9c19e..0142c518781 100644 --- a/jdk/src/share/classes/java/util/GregorianCalendar.java +++ b/jdk/src/share/classes/java/util/GregorianCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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,7 +40,6 @@ package java.util; import java.io.IOException; import java.io.ObjectInputStream; -import sun.util.locale.provider.CalendarDataUtility; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; @@ -722,6 +721,18 @@ public class GregorianCalendar extends Calendar { this.internalSet(MILLISECOND, millis); } + /** + * Constructs an empty GregorianCalendar. + * + * @param zone the given time zone + * @param aLocale the given locale + * @param flag the flag requesting an empty instance + */ + GregorianCalendar(TimeZone zone, Locale locale, boolean flag) { + super(zone, locale); + gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone()); + } + ///////////////// // Public methods ///////////////// diff --git a/jdk/src/share/classes/java/util/JapaneseImperialCalendar.java b/jdk/src/share/classes/java/util/JapaneseImperialCalendar.java index 11b88e68e0f..ed95f96e05d 100644 --- a/jdk/src/share/classes/java/util/JapaneseImperialCalendar.java +++ b/jdk/src/share/classes/java/util/JapaneseImperialCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -301,6 +301,18 @@ class JapaneseImperialCalendar extends Calendar { setTimeInMillis(System.currentTimeMillis()); } + /** + * Constructs an "empty" {@code JapaneseImperialCalendar}. + * + * @param zone the given time zone + * @param aLocale the given locale + * @param flag the flag requesting an empty instance + */ + JapaneseImperialCalendar(TimeZone zone, Locale aLocale, boolean flag) { + super(zone, aLocale); + jdate = jcal.newCalendarDate(zone); + } + /** * Returns {@code "japanese"} as the calendar type of this {@code * JapaneseImperialCalendar}. diff --git a/jdk/src/share/classes/java/util/Locale.java b/jdk/src/share/classes/java/util/Locale.java index 9d469e4660c..198148206d1 100644 --- a/jdk/src/share/classes/java/util/Locale.java +++ b/jdk/src/share/classes/java/util/Locale.java @@ -50,7 +50,6 @@ import java.text.MessageFormat; import java.util.spi.LocaleNameProvider; import sun.security.action.GetPropertyAction; -import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.BaseLocale; import sun.util.locale.InternalLocaleBuilder; import sun.util.locale.LanguageTag; @@ -61,7 +60,9 @@ import sun.util.locale.LocaleSyntaxException; import sun.util.locale.LocaleUtils; import sun.util.locale.ParseStatus; import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.resources.OpenListResourceBundle; +import sun.util.locale.provider.LocaleResources; +import sun.util.locale.provider.LocaleServiceProviderPool; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * A Locale object represents a specific geographical, political, @@ -1779,20 +1780,15 @@ public final class Locale implements Cloneable, Serializable { if (baseLocale.getVariant().length() == 0) return ""; - OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); - String names[] = getDisplayVariantArray(bundle, inLocale); + String names[] = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a list, and use // them to format the list. - String listPattern = null; - String listCompositionPattern = null; - try { - listPattern = bundle.getString("ListPattern"); - listCompositionPattern = bundle.getString("ListCompositionPattern"); - } catch (MissingResourceException e) { - } - return formatList(names, listPattern, listCompositionPattern); + return formatList(names, + lr.getLocaleName("ListPattern"), + lr.getLocaleName("ListCompositionPattern")); } /** @@ -1837,23 +1833,17 @@ public final class Locale implements Cloneable, Serializable { * @throws NullPointerException if inLocale is null */ public String getDisplayName(Locale inLocale) { - OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); String languageName = getDisplayLanguage(inLocale); String scriptName = getDisplayScript(inLocale); String countryName = getDisplayCountry(inLocale); - String[] variantNames = getDisplayVariantArray(bundle, inLocale); + String[] variantNames = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a display name. - String displayNamePattern = null; - String listPattern = null; - String listCompositionPattern = null; - try { - displayNamePattern = bundle.getString("DisplayNamePattern"); - listPattern = bundle.getString("ListPattern"); - listCompositionPattern = bundle.getString("ListCompositionPattern"); - } catch (MissingResourceException e) { - } + String displayNamePattern = lr.getLocaleName("DisplayNamePattern"); + String listPattern = lr.getLocaleName("ListPattern"); + String listCompositionPattern = lr.getLocaleName("ListCompositionPattern"); // The display name consists of a main name, followed by qualifiers. // Typically, the format is "MainName (Qualifier, Qualifier)" but this @@ -2005,7 +1995,7 @@ public final class Locale implements Cloneable, Serializable { * @param bundle the ResourceBundle to use to get the display names * @return an array of display names, possible of zero length. */ - private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { + private String[] getDisplayVariantArray(Locale inLocale) { // Split the variant name into tokens separated by '_'. StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_"); String[] names = new String[tokenizer.countTokens()]; diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index 9d9fbcc8fd1..d79e201ce7a 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -430,32 +430,7 @@ abstract public class TimeZone implements Serializable, Cloneable { } private static String[] getDisplayNames(String id, Locale locale) { - Map>> displayNames = DisplayNames.CACHE; - - SoftReference> ref = displayNames.get(id); - if (ref != null) { - Map perLocale = ref.get(); - if (perLocale != null) { - String[] names = perLocale.get(locale); - if (names != null) { - return names; - } - names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - perLocale.put(locale, names); - } - return names; - } - } - - String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - Map perLocale = new ConcurrentHashMap<>(); - perLocale.put(locale, names); - ref = new SoftReference<>(perLocale); - displayNames.put(id, ref); - } - return names; + return TimeZoneNameUtility.retrieveDisplayNames(id, locale); } /** diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java index aa8210bce4a..08c870f0c22 100644 --- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -35,7 +35,10 @@ package java.util.concurrent; +import java.io.ObjectStreamField; import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * A random number generator isolated to the current thread. Like the @@ -62,46 +65,105 @@ import java.util.Random; * @author Doug Lea */ public class ThreadLocalRandom extends Random { + /* + * This class implements the java.util.Random API (and subclasses + * Random) using a single static instance that accesses random + * number state held in class Thread (primarily, field + * threadLocalRandomSeed). In doing so, it also provides a home + * for managing package-private utilities that rely on exactly the + * same state as needed to maintain the ThreadLocalRandom + * instances. We leverage the need for an initialization flag + * field to also use it as a "probe" -- a self-adjusting thread + * hash used for contention avoidance, as well as a secondary + * simpler (xorShift) random seed that is conservatively used to + * avoid otherwise surprising users by hijacking the + * ThreadLocalRandom sequence. The dual use is a marriage of + * convenience, but is a simple and efficient way of reducing + * application-level overhead and footprint of most concurrent + * programs. + * + * Because this class is in a different package than class Thread, + * field access methods must use Unsafe to bypass access control + * rules. The base functionality of Random methods is + * conveniently isolated in method next(bits), that just reads and + * writes the Thread field rather than its own field. However, to + * conform to the requirements of the Random constructor, during + * construction, the common static ThreadLocalRandom must maintain + * initialization and value fields, mainly for the sake of + * disabling user calls to setSeed while still allowing a call + * from constructor. For serialization compatibility, these + * fields are left with the same declarations as used in the + * previous ThreadLocal-based version of this class, that used + * them differently. Note that serialization is completely + * unnecessary because there is only a static singleton. But these + * mechanics still ensure compatibility across versions. + * + * Per-instance initialization is similar to that in the no-arg + * Random constructor, but we avoid correlation among not only + * initial seeds of those created in different threads, but also + * those created using class Random itself; while at the same time + * not changing any statistical properties. So we use the same + * underlying multiplicative sequence, but start the sequence far + * away from the base version, and then merge (xor) current time + * and per-thread probe bits to generate initial values. + * + * The nextLocalGaussian ThreadLocal supports the very rarely used + * nextGaussian method by providing a holder for the second of a + * pair of them. As is true for the base class version of this + * method, this time/space tradeoff is probably never worthwhile, + * but we provide identical statistical properties. + */ + // same constants as Random, but must be redeclared because private private static final long multiplier = 0x5DEECE66DL; private static final long addend = 0xBL; private static final long mask = (1L << 48) - 1; + private static final int PROBE_INCREMENT = 0x61c88647; + + /** Generates the basis for per-thread initial seed values */ + private static final AtomicLong seedGenerator = + new AtomicLong(1269533684904616924L); + + /** Generates per-thread initialization/probe field */ + private static final AtomicInteger probeGenerator = + new AtomicInteger(0xe80f8647); + + /** Rarely-used holder for the second of a pair of Gaussians */ + private static final ThreadLocal nextLocalGaussian = + new ThreadLocal(); + + /* + * Field used only during singleton initialization + */ + boolean initialized; // true when constructor completes + + /** Constructor used only for static singleton */ + private ThreadLocalRandom() { + initialized = true; // false during super() call + } + + /** The common ThreadLocalRandom */ + static final ThreadLocalRandom instance = new ThreadLocalRandom(); /** - * The random seed. We can't use super.seed. + * Initialize Thread fields for the current thread. Called only + * when Thread.threadLocalRandomProbe is zero, indicating that a + * thread local seed value needs to be generated. Note that even + * though the initialization is purely thread-local, we need to + * rely on (static) atomic generators to initialize the values. */ - private long rnd; - - /** - * Initialization flag to permit calls to setSeed to succeed only - * while executing the Random constructor. We can't allow others - * since it would cause setting seed in one part of a program to - * unintentionally impact other usages by the thread. - */ - boolean initialized; - - // Padding to help avoid memory contention among seed updates in - // different TLRs in the common case that they are located near - // each other. - private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; - - /** - * The actual ThreadLocal - */ - private static final ThreadLocal localRandom = - new ThreadLocal() { - protected ThreadLocalRandom initialValue() { - return new ThreadLocalRandom(); - } - }; - - - /** - * Constructor called only by localRandom.initialValue. - */ - ThreadLocalRandom() { - super(); - initialized = true; + static final void localInit() { + int p = probeGenerator.getAndAdd(PROBE_INCREMENT); + int probe = (p == 0) ? 1 : p; // skip 0 + long current, next; + do { // same sequence as j.u.Random but different initial value + current = seedGenerator.get(); + next = current * 181783497276652981L; + } while (!seedGenerator.compareAndSet(current, next)); + long r = next ^ ((long)probe << 32) ^ System.nanoTime(); + Thread t = Thread.currentThread(); + UNSAFE.putLong(t, SEED, r); + UNSAFE.putInt(t, PROBE, probe); } /** @@ -110,7 +172,9 @@ public class ThreadLocalRandom extends Random { * @return the current thread's {@code ThreadLocalRandom} */ public static ThreadLocalRandom current() { - return localRandom.get(); + if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0) + localInit(); + return instance; } /** @@ -120,14 +184,16 @@ public class ThreadLocalRandom extends Random { * @throws UnsupportedOperationException always */ public void setSeed(long seed) { - if (initialized) + if (initialized) // allow call from super() constructor throw new UnsupportedOperationException(); - rnd = (seed ^ multiplier) & mask; } protected int next(int bits) { - rnd = (rnd * multiplier + addend) & mask; - return (int) (rnd >>> (48-bits)); + Thread t; long r; // read and update per-thread seed + UNSAFE.putLong + (t = Thread.currentThread(), SEED, + r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask); + return (int) (r >>> (48-bits)); } /** @@ -222,5 +288,153 @@ public class ThreadLocalRandom extends Random { return nextDouble() * (bound - least) + least; } + public double nextGaussian() { + // Use nextLocalGaussian instead of nextGaussian field + Double d = nextLocalGaussian.get(); + if (d != null) { + nextLocalGaussian.set(null); + return d.doubleValue(); + } + double v1, v2, s; + do { + v1 = 2 * nextDouble() - 1; // between -1 and 1 + v2 = 2 * nextDouble() - 1; // between -1 and 1 + s = v1 * v1 + v2 * v2; + } while (s >= 1 || s == 0); + double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s); + nextLocalGaussian.set(new Double(v2 * multiplier)); + return v1 * multiplier; + } + + // Within-package utilities + + /* + * Descriptions of the usages of the methods below can be found in + * the classes that use them. Briefly, a thread's "probe" value is + * a non-zero hash code that (probably) does not collide with + * other existing threads with respect to any power of two + * collision space. When it does collide, it is pseudo-randomly + * adjusted (using a Marsaglia XorShift). The nextSecondarySeed + * method is used in the same contexts as ThreadLocalRandom, but + * only for transient usages such as random adaptive spin/block + * sequences for which a cheap RNG suffices and for which it could + * in principle disrupt user-visible statistical properties of the + * main ThreadLocalRandom if we were to use it. + * + * Note: Because of package-protection issues, versions of some + * these methods also appear in some subpackage classes. + */ + + /** + * Returns the probe value for the current thread without forcing + * initialization. Note that invoking ThreadLocalRandom.current() + * can be used to force initialization on zero return. + */ + static final int getProbe() { + return UNSAFE.getInt(Thread.currentThread(), PROBE); + } + + /** + * Pseudo-randomly advances and records the given probe value for the + * given thread. + */ + static final int advanceProbe(int probe) { + probe ^= probe << 13; // xorshift + probe ^= probe >>> 17; + probe ^= probe << 5; + UNSAFE.putInt(Thread.currentThread(), PROBE, probe); + return probe; + } + + /** + * Returns the pseudo-randomly initialized or updated secondary seed. + */ + 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 = (int)UNSAFE.getLong(t, SEED)) == 0) + r = 1; // avoid zero + UNSAFE.putInt(t, SECONDARY, r); + return r; + } + + // Serialization support, maintains original persistent form. + private static final long serialVersionUID = -5851777807851030925L; + + /** + * @serialField rnd long + * @serialField initialized boolean + * @serialField pad0 long + * @serialField pad1 long + * @serialField pad2 long + * @serialField pad3 long + * @serialField pad4 long + * @serialField pad5 long + * @serialField pad6 long + * @serialField pad7 long + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("rnd", long.class), + new ObjectStreamField("initialized", boolean.class), + new ObjectStreamField("pad0", long.class), + new ObjectStreamField("pad1", long.class), + new ObjectStreamField("pad2", long.class), + new ObjectStreamField("pad3", long.class), + new ObjectStreamField("pad4", long.class), + new ObjectStreamField("pad5", long.class), + new ObjectStreamField("pad6", long.class), + new ObjectStreamField("pad7", long.class) }; + + /** + * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it). + */ + private void writeObject(java.io.ObjectOutputStream out) + throws java.io.IOException { + + java.io.ObjectOutputStream.PutField fields = out.putFields(); + fields.put("rnd", 0L); + fields.put("initialized", true); + fields.put("pad0", 0L); + fields.put("pad1", 0L); + fields.put("pad2", 0L); + fields.put("pad3", 0L); + fields.put("pad4", 0L); + fields.put("pad5", 0L); + fields.put("pad6", 0L); + fields.put("pad7", 0L); + out.writeFields(); + } + + /** + * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}. + */ + private Object readResolve() { + return current(); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + 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; + SEED = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSeed")); + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + SECONDARY = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSecondarySeed")); + } catch (Exception e) { + throw new Error(e); + } + } } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java index f1c76b02bff..b48ef72dfc9 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; /** @@ -203,6 +205,92 @@ public class AtomicInteger extends Number implements java.io.Serializable { return getAndAdd(delta) + delta; } + /** + * Atomically updates the current value with the results of + * applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the previous value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the updated value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java index b5578ed93d8..6e4d226ba80 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; /** @@ -245,6 +247,100 @@ public class AtomicIntegerArray implements java.io.Serializable { return getAndAdd(i, delta) + delta; } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(int i, IntUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(int i, IntUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the previous value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(int i, int x, + IntBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the updated value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(int i, int x, + IntBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index e2ae9c4f5dd..fcd5dd05f28 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -264,6 +266,96 @@ public abstract class AtomicIntegerFieldUpdater { return next; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the previous + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the updated + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(T obj, IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(T obj, int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(T obj, int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + /** * Standard hotspot implementation using intrinsics */ diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java index b38cf041fbb..2e58d29b211 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; /** @@ -217,6 +219,92 @@ public class AtomicLong extends Number implements java.io.Serializable { return getAndAdd(delta) + delta; } + /** + * Atomically updates the current value with the results of + * applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the previous value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the updated value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java index 9651426c750..2536a9b8e93 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; /** @@ -244,6 +246,100 @@ public class AtomicLongArray implements java.io.Serializable { return getAndAdd(i, delta) + delta; } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(int i, LongUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(int i, LongUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the previous value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(int i, int x, + LongBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the updated value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(int i, int x, + LongBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index a013680ce7a..a7672263a77 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -267,6 +269,96 @@ public abstract class AtomicLongFieldUpdater { return next; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the previous + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the updated + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(T obj, LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(T obj, long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(T obj, long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + private static class CASUpdater extends AtomicLongFieldUpdater { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java index 94c9edca52a..95b88d127e2 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import sun.misc.Unsafe; /** @@ -141,6 +143,92 @@ public class AtomicReference implements java.io.Serializable { return (V)unsafe.getAndSetObject(this, valueOffset, newValue); } + /** + * Atomically updates the current value with the results of + * applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final V getAndUpdate(UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(); + next = updateFunction.operate(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final V updateAndGet(UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(); + next = updateFunction.operate(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the previous value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final V getAndAccumulate(V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function to the current and given values, + * returning the updated value. The function should be + * side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final V accumulateAndGet(V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index 71308618541..3e6ce969847 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -36,6 +36,8 @@ package java.util.concurrent.atomic; import java.util.Arrays; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import java.lang.reflect.Array; import sun.misc.Unsafe; @@ -199,6 +201,100 @@ public class AtomicReferenceArray implements java.io.Serializable { return compareAndSet(i, expect, update); } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final E getAndUpdate(int i, UnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operate(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final E updateAndGet(int i, UnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operate(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the previous value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final E getAndAccumulate(int i, E x, + BinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the + * results of applying the given function to the current and + * given values, returning the updated value. The function should + * be side-effect-free, since it may be re-applied when attempted + * updates fail due to contention among threads. The function is + * applied with the current value at index {@code i} as its first + * argument, and the given update as the second argument. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final E accumulateAndGet(int i, E x, + BinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 78c636956f6..a92d914ff77 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -183,6 +185,96 @@ public abstract class AtomicReferenceFieldUpdater { return prev; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the previous + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final V getAndUpdate(T obj, UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(obj); + next = updateFunction.operate(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, returning the updated + * value. The function should be side-effect-free, since it may be + * re-applied when attempted updates fail due to contention among threads. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final V updateAndGet(T obj, UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(obj); + next = updateFunction.operate(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the previous value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final V getAndAccumulate(T obj, V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater with the results of applying the given function to the + * current and given values, returning the updated value. The + * function should be side-effect-free, since it may be re-applied + * when attempted updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final V accumulateAndGet(T obj, V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + private static final class AtomicReferenceFieldUpdaterImpl extends AtomicReferenceFieldUpdater { private static final Unsafe unsafe = Unsafe.getUnsafe(); diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java new file mode 100644 index 00000000000..17556500af3 --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java @@ -0,0 +1,239 @@ +/* + * 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.atomic; +import java.io.Serializable; +import java.util.function.DoubleBinaryOperator; + +/** + * One or more variables that together maintain a running {@code double} + * value updated using a supplied function. When updates (method + * {@link #accumulate}) are contended across threads, the set of variables + * may grow dynamically to reduce contention. Method {@link #get} + * (or, equivalently, {@link #doubleValue}) returns the current value + * across the variables maintaining updates. + * + *

    This class is usually preferable to alternatives when multiple + * threads update a common value that is used for purposes such as + * summary statistics that are frequently updated but less frequently + * read. + * + *

    The supplied accumulator function should be side-effect-free, + * since it may be re-applied when attempted updates fail due to + * contention among threads. The function is applied with the current + * value as its first argument, and the given update as the second + * argument. For example, to maintain a running maximum value, you + * could supply {@code Double::max} along with {@code + * Double.NEGATIVE_INFINITY} as the identity. The order of + * accumulation within or across threads is not guaranteed. Thus, this + * class may not be applicable if numerical stability is required, + * especially when combining values of substantially different orders + * of magnitude. + * + *

    Class {@link DoubleAdder} provides analogs of the functionality + * of this class for the common special case of maintaining sums. The + * call {@code new DoubleAdder()} is equivalent to {@code new + * DoubleAccumulator((x, y) -> x + y, 0.0}. + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code equals}, {@code hashCode} and {@code + * compareTo} because instances are expected to be mutated, and so are + * not useful as collection keys. + * + * @since 1.8 + * @author Doug Lea + */ +public class DoubleAccumulator extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + private final DoubleBinaryOperator function; + private final long identity; // use long representation + + /** + * Creates a new instance using the given accumulator function + * and identity element. + */ + public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction, + double identity) { + this.function = accumulatorFunction; + base = this.identity = Double.doubleToRawLongBits(identity); + } + + /** + * Updates with the given value. + * + * @param x the value + */ + public void accumulate(double x) { + Cell[] as; long b, v, r; int m; Cell a; + if ((as = cells) != null || + (r = Double.doubleToRawLongBits + (function.operateAsDouble + (Double.longBitsToDouble(b = base), x))) != b && !casBase(b, r)) { + boolean uncontended = true; + if (as == null || (m = as.length - 1) < 0 || + (a = as[getProbe() & m]) == null || + !(uncontended = + (r = Double.doubleToRawLongBits + (function.operateAsDouble + (Double.longBitsToDouble(v = a.value), x))) == v || + a.cas(v, r))) + doubleAccumulate(x, function, uncontended); + } + } + + /** + * Returns the current value. The returned value is NOT + * an atomic snapshot; invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the value is being calculated might not be + * incorporated. + * + * @return the current value + */ + public double get() { + Cell[] as = cells; Cell a; + double result = Double.longBitsToDouble(base); + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + result = function.operateAsDouble + (result, Double.longBitsToDouble(a.value)); + } + } + return result; + } + + /** + * Resets variables maintaining updates to the identity value. + * This method may be a useful alternative to creating a new + * updater, but is only effective if there are no concurrent + * updates. Because this method is intrinsically racy, it should + * only be used when it is known that no threads are concurrently + * updating. + */ + public void reset() { + Cell[] as = cells; Cell a; + base = identity; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + a.value = identity; + } + } + } + + /** + * Equivalent in effect to {@link #get} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the value before reset + */ + public double getThenReset() { + Cell[] as = cells; Cell a; + double result = Double.longBitsToDouble(base); + base = identity; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) { + double v = Double.longBitsToDouble(a.value); + a.value = identity; + result = function.operateAsDouble(result, v); + } + } + } + return result; + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value + */ + public String toString() { + return Double.toString(get()); + } + + /** + * Equivalent to {@link #get}. + * + * @return the current value + */ + public double doubleValue() { + return get(); + } + + /** + * Returns the {@linkplain #get current value} as a {@code long} + * after a narrowing primitive conversion. + */ + public long longValue() { + return (long)get(); + } + + /** + * Returns the {@linkplain #get current value} as an {@code int} + * after a narrowing primitive conversion. + */ + public int intValue() { + return (int)get(); + } + + /** + * Returns the {@linkplain #get current value} as a {@code float} + * after a narrowing primitive conversion. + */ + public float floatValue() { + return (float)get(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeDouble(get()); + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + cellsBusy = 0; + cells = null; + base = Double.doubleToRawLongBits(s.readDouble()); + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java new file mode 100644 index 00000000000..30ff552747d --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java @@ -0,0 +1,227 @@ +/* + * 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.atomic; +import java.io.Serializable; + +/** + * One or more variables that together maintain an initially zero + * {@code double} sum. When updates (method {@link #add}) are + * contended across threads, the set of variables may grow dynamically + * to reduce contention. Method {@link #sum} (or, equivalently {@link + * #doubleValue}) returns the current total combined across the + * variables maintaining the sum. The order of accumulation within or + * across threads is not guaranteed. Thus, this class may not be + * applicable if numerical stability is required, especially when + * combining values of substantially different orders of magnitude. + * + *

    This class is usually preferable to alternatives when multiple + * threads update a common value that is used for purposes such as + * summary statistics that are frequently updated but less frequently + * read. + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code equals}, {@code hashCode} and {@code + * compareTo} because instances are expected to be mutated, and so are + * not useful as collection keys. + * + * @since 1.8 + * @author Doug Lea + */ +public class DoubleAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Note that we must use "long" for underlying representations, + * because there is no compareAndSet for double, due to the fact + * that the bitwise equals used in any CAS implementation is not + * the same as double-precision equals. However, we use CAS only + * to detect and alleviate contention, for which bitwise equals + * works best anyway. In principle, the long/double conversions + * used here should be essentially free on most platforms since + * they just re-interpret bits. + */ + + /** + * Creates a new adder with initial sum of zero. + */ + public DoubleAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(double x) { + Cell[] as; long b, v; int m; Cell a; + if ((as = cells) != null || + !casBase(b = base, + Double.doubleToRawLongBits + (Double.longBitsToDouble(b) + x))) { + boolean uncontended = true; + if (as == null || (m = as.length - 1) < 0 || + (a = as[getProbe() & m]) == null || + !(uncontended = a.cas(v = a.value, + Double.doubleToRawLongBits + (Double.longBitsToDouble(v) + x)))) + doubleAccumulate(x, null, uncontended); + } + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot; invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. Also, because floating-point arithmetic is not + * strictly associative, the returned result need not be identical + * to the value that would be obtained in a sequential series of + * updates to a single variable. + * + * @return the sum + */ + public double sum() { + Cell[] as = cells; Cell a; + double sum = Double.longBitsToDouble(base); + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + sum += Double.longBitsToDouble(a.value); + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + Cell[] as = cells; Cell a; + base = 0L; // relies on fact that double 0 must have same rep as long + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + a.value = 0L; + } + } + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public double sumThenReset() { + Cell[] as = cells; Cell a; + double sum = Double.longBitsToDouble(base); + base = 0L; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) { + long v = a.value; + a.value = 0L; + sum += Double.longBitsToDouble(v); + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Double.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public double doubleValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as a {@code long} after a + * narrowing primitive conversion. + */ + public long longValue() { + return (long)sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a + * narrowing primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a narrowing primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeDouble(sum()); + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + cellsBusy = 0; + cells = null; + base = Double.doubleToRawLongBits(s.readDouble()); + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java b/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java new file mode 100644 index 00000000000..855b09e44de --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java @@ -0,0 +1,236 @@ +/* + * 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.atomic; +import java.io.Serializable; +import java.util.function.LongBinaryOperator; + +/** + * One or more variables that together maintain a running {@code long} + * value updated using a supplied function. When updates (method + * {@link #accumulate}) are contended across threads, the set of variables + * may grow dynamically to reduce contention. Method {@link #get} + * (or, equivalently, {@link #longValue}) returns the current value + * across the variables maintaining updates. + * + *

    This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common value that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

    The order of accumulation within or across threads is not + * guaranteed and cannot be depended upon, so this class is only + * applicable to functions for which the order of accumulation does + * not matter. The supplied accumulator function should be + * side-effect-free, since it may be re-applied when attempted updates + * fail due to contention among threads. The function is applied with + * the current value as its first argument, and the given update as + * the second argument. For example, to maintain a running maximum + * value, you could supply {@code Long::max} along with {@code + * Long.MIN_VALUE} as the identity. + * + *

    Class {@link LongAdder} provides analogs of the functionality of + * this class for the common special case of maintaining counts and + * sums. The call {@code new LongAdder()} is equivalent to {@code new + * LongAccumulator((x, y) -> x + y, 0L}. + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code equals}, {@code hashCode} and {@code + * compareTo} because instances are expected to be mutated, and so are + * not useful as collection keys. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAccumulator extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + private final LongBinaryOperator function; + private final long identity; + + /** + * Creates a new instance using the given accumulator function + * and identity element. + */ + public LongAccumulator(LongBinaryOperator accumulatorFunction, + long identity) { + this.function = accumulatorFunction; + base = this.identity = identity; + } + + /** + * Updates with the given value. + * + * @param x the value + */ + public void accumulate(long x) { + Cell[] as; long b, v, r; int m; Cell a; + if ((as = cells) != null || + (r = function.operateAsLong(b = base, x)) != b && !casBase(b, r)) { + boolean uncontended = true; + if (as == null || (m = as.length - 1) < 0 || + (a = as[getProbe() & m]) == null || + !(uncontended = + (r = function.operateAsLong(v = a.value, x)) == v || + a.cas(v, r))) + longAccumulate(x, function, uncontended); + } + } + + /** + * Returns the current value. The returned value is NOT + * an atomic snapshot; invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the value is being calculated might not be + * incorporated. + * + * @return the current value + */ + public long get() { + Cell[] as = cells; Cell a; + long result = base; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + result = function.operateAsLong(result, a.value); + } + } + return result; + } + + /** + * Resets variables maintaining updates to the identity value. + * This method may be a useful alternative to creating a new + * updater, but is only effective if there are no concurrent + * updates. Because this method is intrinsically racy, it should + * only be used when it is known that no threads are concurrently + * updating. + */ + public void reset() { + Cell[] as = cells; Cell a; + base = identity; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + a.value = identity; + } + } + } + + /** + * Equivalent in effect to {@link #get} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the value before reset + */ + public long getThenReset() { + Cell[] as = cells; Cell a; + long result = base; + base = identity; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) { + long v = a.value; + a.value = identity; + result = function.operateAsLong(result, v); + } + } + } + return result; + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value + */ + public String toString() { + return Long.toString(get()); + } + + /** + * Equivalent to {@link #get}. + * + * @return the current value + */ + public long longValue() { + return get(); + } + + /** + * Returns the {@linkplain #get current value} as an {@code int} + * after a narrowing primitive conversion. + */ + public int intValue() { + return (int)get(); + } + + /** + * Returns the {@linkplain #get current value} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)get(); + } + + /** + * Returns the {@linkplain #get current value} as a {@code double} + * after a widening primitive conversion. + */ + public double doubleValue() { + return (double)get(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(get()); + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + cellsBusy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/LongAdder.java b/jdk/src/share/classes/java/util/concurrent/atomic/LongAdder.java new file mode 100644 index 00000000000..70c5bed4ccf --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/atomic/LongAdder.java @@ -0,0 +1,228 @@ +/* + * 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.atomic; +import java.io.Serializable; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

    This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

    LongAdders can be used with a {@link + * java.util.concurrent.ConcurrentHashMap} to maintain a scalable + * frequency map (a form of histogram or multiset). For example, to + * add a count to a {@code ConcurrentHashMap freqs}, + * initializing if not already present, you can use {@code + * freqs.computeIfAbsent(k -> new LongAdder()).increment();} + * + *

    This class extends {@link Number}, but does not define + * methods such as {@code equals}, {@code hashCode} and {@code + * compareTo} because instances are expected to be mutated, and so are + * not useful as collection keys. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; int m; Cell a; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + if (as == null || (m = as.length - 1) < 0 || + (a = as[getProbe() & m]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + longAccumulate(x, null, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot; invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + Cell[] as = cells; Cell a; + long sum = base; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + Cell[] as = cells; Cell a; + base = 0L; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + a.value = 0L; + } + } + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + Cell[] as = cells; Cell a; + long sum = base; + base = 0L; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + cellsBusy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java b/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java new file mode 100644 index 00000000000..03969d76dca --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java @@ -0,0 +1,417 @@ +/* + * 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.atomic; +import java.util.function.LongBinaryOperator; +import java.util.function.DoubleBinaryOperator; +import java.util.concurrent.ThreadLocalRandom; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("cellsBusy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock; when the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * The Thread probe fields maintained via ThreadLocalRandom serve + * as per-thread hash codes. We let them remain uninitialized as + * zero (if they come in this way) until they contend at slot + * 0. They are then initialized to values that typically do not + * often conflict with others. Contention and/or table collisions + * are indicated by failed CASes when performing an update + * operation. Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long valueOffset; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class ak = Cell.class; + valueOffset = UNSAFE.objectFieldOffset + (ak.getDeclaredField("value")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int cellsBusy; + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, BASE, cmp, val); + } + + /** + * CASes the cellsBusy field from 0 to 1 to acquire lock. + */ + final boolean casCellsBusy() { + return UNSAFE.compareAndSwapInt(this, CELLSBUSY, 0, 1); + } + + /** + * Returns the probe value for the current thread. + * Duplicated from ThreadLocalRandom because of packaging restrictions. + */ + static final int getProbe() { + return UNSAFE.getInt(Thread.currentThread(), PROBE); + } + + /** + * Pseudo-randomly advances and records the given probe value for the + * given thread. + * Duplicated from ThreadLocalRandom because of packaging restrictions. + */ + static final int advanceProbe(int probe) { + probe ^= probe << 13; // xorshift + probe ^= probe >>> 17; + probe ^= probe << 5; + UNSAFE.putInt(Thread.currentThread(), PROBE, probe); + return probe; + } + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param fn the update function, or null for add (this convention + * avoids the need for an extra field or function in LongAdder). + * @param wasUncontended false if CAS failed before call + */ + final void longAccumulate(long x, LongBinaryOperator fn, + boolean wasUncontended) { + int h; + if ((h = getProbe()) == 0) { + ThreadLocalRandom.current(); // force initialization + h = getProbe(); + wasUncontended = true; + } + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (cellsBusy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (cellsBusy == 0 && casCellsBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + cellsBusy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, ((fn == null) ? v + x : + fn.operateAsLong(v, x)))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (cellsBusy == 0 && casCellsBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + cellsBusy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h = advanceProbe(h); + } + else if (cellsBusy == 0 && cells == as && casCellsBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + cellsBusy = 0; + } + if (init) + break; + } + else if (casBase(v = base, ((fn == null) ? v + x : + fn.operateAsLong(v, x)))) + break; // Fall back on using base + } + } + + /** + * Same as longAccumulate, but injecting long/double conversions + * in too many places to sensibly merge with long version, given + * the low-overhead requirements of this class. So must instead be + * maintained by copy/paste/adapt. + */ + final void doubleAccumulate(double x, DoubleBinaryOperator fn, + boolean wasUncontended) { + int h; + if ((h = getProbe()) == 0) { + ThreadLocalRandom.current(); // force initialization + h = getProbe(); + wasUncontended = true; + } + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (cellsBusy == 0) { // Try to attach new Cell + Cell r = new Cell(Double.doubleToRawLongBits(x)); + if (cellsBusy == 0 && casCellsBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + cellsBusy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, + ((fn == null) ? + Double.doubleToRawLongBits + (Double.longBitsToDouble(v) + x) : + Double.doubleToRawLongBits + (fn.operateAsDouble + (Double.longBitsToDouble(v), x))))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (cellsBusy == 0 && casCellsBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + cellsBusy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h = advanceProbe(h); + } + else if (cellsBusy == 0 && cells == as && casCellsBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(Double.doubleToRawLongBits(x)); + cells = rs; + init = true; + } + } finally { + cellsBusy = 0; + } + if (init) + break; + } + else if (casBase(v = base, + ((fn == null) ? + Double.doubleToRawLongBits + (Double.longBitsToDouble(v) + x) : + Double.doubleToRawLongBits + (fn.operateAsDouble + (Double.longBitsToDouble(v), x))))) + break; // Fall back on using base + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long BASE; + private static final long CELLSBUSY; + private static final long PROBE; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class sk = Striped64.class; + BASE = UNSAFE.objectFieldOffset + (sk.getDeclaredField("base")); + CELLSBUSY = UNSAFE.objectFieldOffset + (sk.getDeclaredField("cellsBusy")); + Class tk = Thread.class; + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + } catch (Exception e) { + throw new Error(e); + } + } + +} diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index e1f2bbaf5f8..4e52c235c0c 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -30,6 +30,7 @@ import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.security.*; import java.lang.ref.WeakReference; +import java.util.function.Supplier; /** * A Logger object is used to log messages for a specific @@ -96,6 +97,33 @@ import java.lang.ref.WeakReference; * for example a format string "{0} {1}" would format two parameters * as strings. *

    + * A set of methods alternatively take a "msgSupplier" instead of a "msg" + * argument. These methods take a {@link Supplier}{@code } function + * which is invoked to construct the desired log message only when the message + * actually is to be logged based on the effective log level thus eliminating + * unnecessary message construction. For example, if the developer wants to + * log system health status for diagnosis, with the String-accepting version, + * the code would look like: +

    +
    +   class DiagnosisMessages {
    +     static String systemHealthStatus() {
    +       // collect system health information
    +       ...
    +     }
    +   }
    +   ...
    +   logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
    + 
    + * With the above code, the health status is collected unnecessarily even when + * the log level FINER is disabled. With the Supplier-accepting version as + * below, the status will only be collected when the log level FINER is + * enabled. +
    +
    +   logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
    + 
    + *

    * When mapping ResourceBundle names to ResourceBundles, the Logger * will first try to use the Thread's ContextClassLoader. If that * is null it will try the SystemClassLoader instead. As a temporary @@ -566,6 +594,27 @@ public class Logger { doLog(lr); } + /** + * Log a message, which is only to be constructed if the logging level + * is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the given message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param msgSupplier A function, which when called, produces the + * desired log message + */ + public void log(Level level, Supplier msgSupplier) { + if (level.intValue() < levelValue || levelValue == offValue) { + return; + } + LogRecord lr = new LogRecord(level, msgSupplier.get()); + doLog(lr); + } + /** * Log a message, with one object parameter. *

    @@ -615,7 +664,7 @@ public class Logger { * which is forwarded to all registered output handlers. *

    * Note that the thrown argument is stored in the LogRecord thrown - * property, rather than the LogRecord parameters property. Thus is it + * property, rather than the LogRecord parameters property. Thus it is * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    @@ -632,6 +681,34 @@ public class Logger { doLog(lr); } + /** + * Log a lazily constructed message, with associated Throwable information. + *

    + * If the logger is currently enabled for the given message level then the + * message is constructed by invoking the provided supplier function. The + * message and the given {@link Throwable} are then stored in a {@link + * LogRecord} which is forwarded to all registered output handlers. + *

    + * Note that the thrown argument is stored in the LogRecord thrown + * property, rather than the LogRecord parameters property. Thus it is + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param thrown Throwable associated with log message. + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void log(Level level, Throwable thrown, Supplier msgSupplier) { + if (level.intValue() < levelValue || levelValue == offValue) { + return; + } + LogRecord lr = new LogRecord(level, msgSupplier.get()); + lr.setThrown(thrown); + doLog(lr); + } + //================================================================ // Start of convenience methods WITH className and methodName //================================================================ @@ -659,6 +736,33 @@ public class Logger { doLog(lr); } + /** + * Log a lazily constructed message, specifying source class and method, + * with no arguments. + *

    + * If the logger is currently enabled for the given message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void logp(Level level, String sourceClass, String sourceMethod, + Supplier msgSupplier) { + if (level.intValue() < levelValue || levelValue == offValue) { + return; + } + LogRecord lr = new LogRecord(level, msgSupplier.get()); + lr.setSourceClassName(sourceClass); + lr.setSourceMethodName(sourceMethod); + doLog(lr); + } + /** * Log a message, specifying source class and method, * with a single object parameter to the log message. @@ -721,7 +825,7 @@ public class Logger { * which is forwarded to all registered output handlers. *

    * Note that the thrown argument is stored in the LogRecord thrown - * property, rather than the LogRecord parameters property. Thus is it + * property, rather than the LogRecord parameters property. Thus it is * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    @@ -732,7 +836,7 @@ public class Logger { * @param thrown Throwable associated with log message. */ public void logp(Level level, String sourceClass, String sourceMethod, - String msg, Throwable thrown) { + String msg, Throwable thrown) { if (level.intValue() < levelValue || levelValue == offValue) { return; } @@ -743,6 +847,40 @@ public class Logger { doLog(lr); } + /** + * Log a lazily constructed message, specifying source class and method, + * with associated Throwable information. + *

    + * If the logger is currently enabled for the given message level then the + * message is constructed by invoking the provided supplier function. The + * message and the given {@link Throwable} are then stored in a {@link + * LogRecord} which is forwarded to all registered output handlers. + *

    + * Note that the thrown argument is stored in the LogRecord thrown + * property, rather than the LogRecord parameters property. Thus it is + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param thrown Throwable associated with log message. + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void logp(Level level, String sourceClass, String sourceMethod, + Throwable thrown, Supplier msgSupplier) { + if (level.intValue() < levelValue || levelValue == offValue) { + return; + } + LogRecord lr = new LogRecord(level, msgSupplier.get()); + lr.setSourceClassName(sourceClass); + lr.setSourceMethodName(sourceMethod); + lr.setThrown(thrown); + doLog(lr); + } + //========================================================================= // Start of convenience methods WITH className, methodName and bundle name. @@ -869,7 +1007,7 @@ public class Logger { * then the msg string is not localized. *

    * Note that the thrown argument is stored in the LogRecord thrown - * property, rather than the LogRecord parameters property. Thus is it + * property, rather than the LogRecord parameters property. Thus it is * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    @@ -1014,7 +1152,7 @@ public class Logger { * LogRecord's message is set to "THROW". *

    * Note that the thrown argument is stored in the LogRecord thrown - * property, rather than the LogRecord parameters property. Thus is it + * property, rather than the LogRecord parameters property. Thus it is * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    @@ -1149,6 +1287,130 @@ public class Logger { log(Level.FINEST, msg); } + //======================================================================= + // Start of simple convenience methods using level names as method names + // and use Supplier + //======================================================================= + + /** + * Log a SEVERE message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the SEVERE message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void severe(Supplier msgSupplier) { + log(Level.SEVERE, msgSupplier); + } + + /** + * Log a WARNING message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the WARNING message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void warning(Supplier msgSupplier) { + log(Level.WARNING, msgSupplier); + } + + /** + * Log a INFO message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the INFO message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void info(Supplier msgSupplier) { + log(Level.INFO, msgSupplier); + } + + /** + * Log a CONFIG message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the CONFIG message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void config(Supplier msgSupplier) { + log(Level.CONFIG, msgSupplier); + } + + /** + * Log a FINE message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the FINE message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void fine(Supplier msgSupplier) { + log(Level.FINE, msgSupplier); + } + + /** + * Log a FINER message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the FINER message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void finer(Supplier msgSupplier) { + log(Level.FINER, msgSupplier); + } + + /** + * Log a FINEST message, which is only to be constructed if the logging + * level is such that the message will actually be logged. + *

    + * If the logger is currently enabled for the FINEST message + * level then the message is constructed by invoking the provided + * supplier function and forwarded to all the registered output + * Handler objects. + *

    + * @param msgSupplier A function, which when called, produces the + * desired log message + * @since 1.8 + */ + public void finest(Supplier msgSupplier) { + log(Level.FINEST, msgSupplier); + } + //================================================================ // End of convenience methods //================================================================ diff --git a/jdk/src/share/classes/java/util/spi/CalendarNameProvider.java b/jdk/src/share/classes/java/util/spi/CalendarNameProvider.java index 8e8d54e8ecd..c0a0ad806aa 100644 --- a/jdk/src/share/classes/java/util/spi/CalendarNameProvider.java +++ b/jdk/src/share/classes/java/util/spi/CalendarNameProvider.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 @@ -134,6 +134,26 @@ import java.util.Map; * specified. See also the * Year representation in {@code SimpleDateFormat}. * + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * *
    {@code "roc"}{@link Calendar#ERA}0Before R.O.C.
    1R.O.C.
    {@code "islamic"}{@link Calendar#ERA}0Before AH
    1Anno Hijrah (AH)
    * *

    Calendar field value names for {@code "gregory"} must be consistent with diff --git a/jdk/src/share/classes/javax/crypto/SecretKey.java b/jdk/src/share/classes/javax/crypto/SecretKey.java index 05d0e11319c..e03639ab42a 100644 --- a/jdk/src/share/classes/javax/crypto/SecretKey.java +++ b/jdk/src/share/classes/javax/crypto/SecretKey.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 @@ -27,20 +27,28 @@ package javax.crypto; /** * A secret (symmetric) key. - * - *

    This interface contains no methods or constants. - * Its only purpose is to group (and provide type safety for) secret keys. - * - *

    Provider implementations of this interface must overwrite the - * equals and hashCode methods inherited from - * java.lang.Object, so that secret keys are compared based on + * The purpose of this interface is to group (and provide type safety + * for) all secret key interfaces. + *

    + * Provider implementations of this interface must overwrite the + * {@code equals} and {@code hashCode} methods inherited from + * {@link java.lang.Object}, so that secret keys are compared based on * their underlying key material and not based on reference. + * Implementations should override the default {@code destroy} and + * {@code isDestroyed} methods from the + * {@link javax.security.auth.Destroyable} interface to enable + * sensitive key information to be destroyed, cleared, or in the case + * where such information is immutable, unreferenced. + * Finally, since {@code SecretKey} is {@code Serializable}, implementations + * should also override + * {@link java.io.ObjectOutputStream#writeObject(java.lang.Object)} + * to prevent keys that have been destroyed from being serialized. * - *

    Keys that implement this interface return the string RAW - * as their encoding format (see getFormat), and return the - * raw key bytes as the result of a getEncoded method call. (The - * getFormat and getEncoded methods are inherited - * from the java.security.Key parent interface.) + *

    Keys that implement this interface return the string {@code RAW} + * as their encoding format (see {@code getFormat}), and return the + * raw key bytes as the result of a {@code getEncoded} method call. (The + * {@code getFormat} and {@code getEncoded} methods are inherited + * from the {@link java.security.Key} parent interface.) * * @author Jan Luehe * @@ -49,7 +57,9 @@ package javax.crypto; * @since 1.4 */ -public interface SecretKey extends java.security.Key { +public interface SecretKey extends + java.security.Key, javax.security.auth.Destroyable { + /** * The class fingerprint that is set to indicate serialization * compatibility since J2SE 1.4. diff --git a/jdk/src/share/classes/javax/imageio/spi/IIORegistry.java b/jdk/src/share/classes/javax/imageio/spi/IIORegistry.java index 1baf476ca32..36deb519909 100644 --- a/jdk/src/share/classes/javax/imageio/spi/IIORegistry.java +++ b/jdk/src/share/classes/javax/imageio/spi/IIORegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -64,9 +64,9 @@ import java.util.ServiceConfigurationError; * ImageWriter, ImageTranscoder, * ImageInputStream, and ImageOutputStream. * - *

    Service providers found on the system classpath (e.g., - * the jre/lib/ext directory in Sun's implementation of - * JDK) are automatically loaded as soon as this class is + *

    Service providers found on the system classpath (typically + * the lib/ext directory in the Java + * installation directory) are automatically loaded as soon as this class is * instantiated. * *

    When the registerApplicationClasspathSpis method @@ -226,8 +226,10 @@ public final class IIORegistry extends ServiceRegistry { private void registerInstalledProviders() { /* - We need load installed providers from lib/ext - directory in the privileged mode in order to + We need to load installed providers from the + system classpath (typically the lib/ext + directory in in the Java installation directory) + in the privileged mode in order to be able read corresponding jar files even if file read capability is restricted (like the applet context case). diff --git a/jdk/src/share/classes/javax/management/MXBean.java b/jdk/src/share/classes/javax/management/MXBean.java index c691438737f..4ff10d360af 100644 --- a/jdk/src/share/classes/javax/management/MXBean.java +++ b/jdk/src/share/classes/javax/management/MXBean.java @@ -907,6 +907,14 @@ public interface ModuleMXBean {

  • Otherwise, J is not reconstructible.

  • +

    Rule 2 is not applicable to subset Profiles of Java SE that do not + include the {@code java.beans} package. When targeting a runtime that does + not include the {@code java.beans} package, and where there is a mismatch + between the compile-time and runtime environment whereby J is + compiled with a public constructor and the {@code ConstructorProperties} + annotation, then J is not reconstructible unless another rule + applies.

    +

    Here are examples showing different ways to code a type {@code NamedNumber} that consists of an {@code int} and a {@code String}. In each case, the {@code CompositeType} looks like this:

    diff --git a/jdk/src/share/classes/javax/management/monitor/package.html b/jdk/src/share/classes/javax/management/monitor/package.html index 282dd926369..a5050d77f0a 100644 --- a/jdk/src/share/classes/javax/management/monitor/package.html +++ b/jdk/src/share/classes/javax/management/monitor/package.html @@ -60,19 +60,20 @@ questions. v. A value x is extracted from v as follows:

      +
    • If v is a {@link javax.management.openmbean.CompositeData CompositeData} and if v.{@link javax.management.openmbean.CompositeData#get(String) get}(e) returns a value then x is that value.
    • If v is an array and e is the string "length" then x is the length of the array.
    • -
    • If the above rules do not produce a value, and if {@link - java.beans.Introspector#getBeanInfo(Class) Introspector.getBeanInfo} - for the class of v (v.getClass()) contains a - {@link java.beans.PropertyDescriptor PropertyDescriptor} with the name - e, then x is the result of calling the property's {@link - java.beans.PropertyDescriptor#getReadMethod() read method} on - v.
    • + +
    • If the above rules do not produce a value, and if introspection, as + if by calling {@link java.beans.Introspector#getBeanInfo(Class) + Introspector.getBeanInfo}, for the class of v + (v.getClass()) identifies a property with the name + e, then x is the result of reading the property value.
    • +

    The third rule means for example that if the attribute diff --git a/jdk/src/share/classes/javax/security/auth/Destroyable.java b/jdk/src/share/classes/javax/security/auth/Destroyable.java index 32f81cf2f42..5afb6aa810b 100644 --- a/jdk/src/share/classes/javax/security/auth/Destroyable.java +++ b/jdk/src/share/classes/javax/security/auth/Destroyable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -42,21 +42,27 @@ public interface Destroyable { * IllegalStateException being thrown. * *

    + * The default implementation throws {@code DestroyFailedException}. * * @exception DestroyFailedException if the destroy operation fails.

    * * @exception SecurityException if the caller does not have permission * to destroy this Object. */ - void destroy() throws DestroyFailedException; + public default void destroy() throws DestroyFailedException { + throw new DestroyFailedException(); + } /** * Determine if this Object has been destroyed. * *

    + * The default implementation returns false. * * @return true if this Object has been destroyed, * false otherwise. */ - boolean isDestroyed(); + public default boolean isDestroyed() { + return false; + } } diff --git a/jdk/src/share/classes/javax/sound/midi/MidiSystem.java b/jdk/src/share/classes/javax/sound/midi/MidiSystem.java index 7a3b186d92e..9d6763a6406 100644 --- a/jdk/src/share/classes/javax/sound/midi/MidiSystem.java +++ b/jdk/src/share/classes/javax/sound/midi/MidiSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -68,8 +68,10 @@ import com.sun.media.sound.MidiDeviceTransmitterEnvelope; * *

    Properties can be used to specify default MIDI devices. * Both system properties and a properties file are considered. - * The properties file is "lib/sound.properties" in the JRE - * directory. If a property exists both as a system property and in the + * The sound.properties properties file is read from + * an implementation-specific location (typically it is the lib + * directory in the Java installation directory). + * If a property exists both as a system property and in the * properties file, the system property takes precedence. If none is * specified, a suitable default is chosen among the available devices. * The syntax of the properties file is specified in diff --git a/jdk/src/share/classes/javax/sound/sampled/AudioSystem.java b/jdk/src/share/classes/javax/sound/sampled/AudioSystem.java index 9a47d9f4632..cf06ca25741 100644 --- a/jdk/src/share/classes/javax/sound/sampled/AudioSystem.java +++ b/jdk/src/share/classes/javax/sound/sampled/AudioSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -63,9 +63,10 @@ import com.sun.media.sound.JDK13Services; *

    Properties can be used to specify the default mixer * for specific line types. * Both system properties and a properties file are considered. - * In the Oracle reference implementation, the properties file is - * "lib/sound.properties" in the JRE - * directory. If a property exists both as a system property and in the + * The sound.properties properties file is read from + * an implementation-specific location (typically it is the lib + * directory in the Java installation directory). + * If a property exists both as a system property and in the * properties file, the system property takes precedence. If none is * specified, a suitable default is chosen among the available devices. * The syntax of the properties file is specified in diff --git a/jdk/src/share/classes/javax/sql/DataSource.java b/jdk/src/share/classes/javax/sql/DataSource.java index 81e5d98dfaa..d4d9d70ddd4 100644 --- a/jdk/src/share/classes/javax/sql/DataSource.java +++ b/jdk/src/share/classes/javax/sql/DataSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, 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 @@ -31,69 +31,79 @@ import java.sql.Wrapper; /** *

    A factory for connections to the physical data source that this - * DataSource object represents. An alternative to the - * DriverManager facility, a DataSource object + * {@code DataSource} object represents. An alternative to the + * {@code DriverManager} facility, a {@code DataSource} object * is the preferred means of getting a connection. An object that implements - * the DataSource interface will typically be + * the {@code DataSource} interface will typically be * registered with a naming service based on the * JavaTM Naming and Directory (JNDI) API. *

    - * The DataSource interface is implemented by a driver vendor. + * The {@code DataSource} interface is implemented by a driver vendor. * There are three types of implementations: *

      - *
    1. Basic implementation -- produces a standard Connection + *
    2. Basic implementation -- produces a standard {@code Connection} * object - *
    3. Connection pooling implementation -- produces a Connection + *
    4. Connection pooling implementation -- produces a {@code Connection} * object that will automatically participate in connection pooling. This * implementation works with a middle-tier connection pooling manager. *
    5. Distributed transaction implementation -- produces a - * Connection object that may be used for distributed + * {@code Connection} object that may be used for distributed * transactions and almost always participates in connection pooling. * This implementation works with a middle-tier * transaction manager and almost always with a connection * pooling manager. *
    *

    - * A DataSource object has properties that can be modified + * A {@code DataSource} object has properties that can be modified * when necessary. For example, if the data source is moved to a different * server, the property for the server can be changed. The benefit is that * because the data source's properties can be changed, any code accessing * that data source does not need to be changed. *

    - * A driver that is accessed via a DataSource object does not - * register itself with the DriverManager. Rather, a - * DataSource object is retrieved though a lookup operation - * and then used to create a Connection object. With a basic - * implementation, the connection obtained through a DataSource + * A driver that is accessed via a {@code DataSource} object does not + * register itself with the {@code DriverManager}. Rather, a + * {@code DataSource} object is retrieved though a lookup operation + * and then used to create a {@code Connection} object. With a basic + * implementation, the connection obtained through a {@code DataSource} * object is identical to a connection obtained through the - * DriverManager facility. + * {@code DriverManager} facility. + *

    + * An implementation of {@code DataSource} must include a public no-arg + * constructor. * * @since 1.4 */ -public interface DataSource extends CommonDataSource,Wrapper { +public interface DataSource extends CommonDataSource, Wrapper { /** *

    Attempts to establish a connection with the data source that - * this DataSource object represents. + * this {@code DataSource} object represents. * * @return a connection to the data source * @exception SQLException if a database access error occurs + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt */ Connection getConnection() throws SQLException; /** *

    Attempts to establish a connection with the data source that - * this DataSource object represents. + * this {@code DataSource} object represents. * * @param username the database user on whose behalf the connection is * being made * @param password the user's password * @return a connection to the data source * @exception SQLException if a database access error occurs + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt * @since 1.4 */ Connection getConnection(String username, String password) throws SQLException; - } diff --git a/jdk/src/share/classes/javax/sql/XADataSource.java b/jdk/src/share/classes/javax/sql/XADataSource.java index 1d4c300810d..325f015f733 100644 --- a/jdk/src/share/classes/javax/sql/XADataSource.java +++ b/jdk/src/share/classes/javax/sql/XADataSource.java @@ -28,12 +28,14 @@ package javax.sql; import java.sql.*; /** - * A factory for XAConnection objects that is used internally. - * An object that implements the XADataSource interface is + * A factory for {@code XAConnection} objects that is used internally. + * An object that implements the {@code XADataSource} interface is * typically registered with a naming service that uses the * Java Naming and Directory InterfaceTM * (JNDI). - * + *

    + * An implementation of {@code XADataSource} must include a public no-arg + * constructor. * @since 1.4 */ @@ -43,12 +45,16 @@ public interface XADataSource extends CommonDataSource { * Attempts to establish a physical database connection that can be * used in a distributed transaction. * - * @return an XAConnection object, which represents a + * @return an {@code XAConnection} object, which represents a * physical connection to a data source, that can be used in * a distributed transaction * @exception SQLException if a database access error occurs * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt * @since 1.4 */ XAConnection getXAConnection() throws SQLException; @@ -60,12 +66,16 @@ public interface XADataSource extends CommonDataSource { * * @param user the database user on whose behalf the connection is being made * @param password the user's password - * @return an XAConnection object, which represents a + * @return an {@code XAConnection} object, which represents a * physical connection to a data source, that can be used in * a distributed transaction * @exception SQLException if a database access error occurs * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value specified by the {@code setLoginTimeout} method + * has been exceeded and has at least tried to cancel the + * current database connection attempt * @since 1.4 */ XAConnection getXAConnection(String user, String password) diff --git a/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java b/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java index adf2e51dd4e..1019b8de19f 100644 --- a/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java +++ b/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java @@ -4175,43 +4175,47 @@ public abstract class BaseRowSet implements Serializable, Cloneable { /** - * Sets the designated parameter to the given java.sql.SQLXML object. The driver converts this to an - * SQL XML value when it sends it to the database. - * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param xmlObject a SQLXML object that maps an SQL XML value - * @throws SQLException if a database access error occurs, this method - * is called on a closed result set, - * the java.xml.transform.Result, - * Writer or OutputStream has not been closed - * for the SQLXML object or - * if there is an error processing the XML value. The getCause method - * of the exception may provide a more detailed exception, for example, if the - * stream does not contain valid XML. - * @since 1.6 - */ - public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + * Sets the designated parameter to the given java.sql.SQLXML object. The driver converts this to an + * SQL XML value when it sends it to the database. + * @param parameterIndex index of the first parameter is 1, the second is 2, ... + * @param xmlObject a SQLXML object that maps an SQL XML value + * @throws SQLException if a database access error occurs, this method + * is called on a closed result set, + * the java.xml.transform.Result, + * Writer or OutputStream has not been closed + * for the SQLXML object or + * if there is an error processing the XML value. The getCause method + * of the exception may provide a more detailed exception, for example, if the + * stream does not contain valid XML. + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * @since 1.6 + */ + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException{ + throw new SQLFeatureNotSupportedException("Feature not supported"); + } - /** - * Sets the designated parameter to the given java.sql.SQLXML object. The driver converts this to an - * SQL XML value when it sends it to the database. - * @param parameterName the name of the parameter - * @param xmlObject a SQLXML object that maps an SQL XML value - * @throws SQLException if a database access error occurs, this method - * is called on a closed result set, - * the java.xml.transform.Result, - * Writer or OutputStream has not been closed - * for the SQLXML object or - * if there is an error processing the XML value. The getCause method - * of the exception may provide a more detailed exception, for example, if the - * stream does not contain valid XML. - * @since 1.6 - */ - public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + /** + * Sets the designated parameter to the given java.sql.SQLXML object. The driver converts this to an + * SQL XML value when it sends it to the database. + * @param parameterName the name of the parameter + * @param xmlObject a SQLXML object that maps an SQL XML value + * @throws SQLException if a database access error occurs, this method + * is called on a closed result set, + * the java.xml.transform.Result, + * Writer or OutputStream has not been closed + * for the SQLXML object or + * if there is an error processing the XML value. The getCause method + * of the exception may provide a more detailed exception, for example, if the + * stream does not contain valid XML. + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * @since 1.6 + */ + public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException{ + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** @@ -4222,27 +4226,31 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @param parameterIndex the first parameter is 1, the second is 2, ... * @param x the parameter value * @throws SQLException if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method * * @since 1.6 */ public void setRowId(int parameterIndex, RowId x) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** - * Sets the designated parameter to the given java.sql.RowId object. The - * driver converts this to a SQL ROWID when it sends it to the - * database. - * - * @param parameterName the name of the parameter - * @param x the parameter value - * @throws SQLException if a database access error occurs - * @since 1.6 - */ + * Sets the designated parameter to the given java.sql.RowId object. The + * driver converts this to a SQL ROWID when it sends it to the + * database. + * + * @param parameterName the name of the parameter + * @param x the parameter value + * @throws SQLException if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * @since 1.6 + */ public void setRowId(String parameterName, RowId x) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** * Sets the designated paramter to the given String object. @@ -4257,11 +4265,13 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @throws SQLException if the driver does not support national * character sets; if the driver can detect that a data conversion * error could occur ; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method * @since 1.6 */ - public void setNString(int parameterIndex, String value) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + public void setNString(int parameterIndex, String value) throws SQLException{ + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** @@ -4273,12 +4283,14 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @throws SQLException if the driver does not support national * character sets; if the driver can detect that a data conversion * error could occur; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method * @since 1.6 */ public void setNString(String parameterName, String value) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** @@ -4292,11 +4304,13 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @throws SQLException if the driver does not support national * character sets; if the driver can detect that a data conversion * error could occur ; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method * @since 1.6 */ - public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException{ + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** @@ -4310,12 +4324,14 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @throws SQLException if the driver does not support national * character sets; if the driver can detect that a data conversion * error could occur; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method * @since 1.6 */ public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + throw new SQLFeatureNotSupportedException("Feature not supported"); + } /** @@ -4345,119 +4361,125 @@ public abstract class BaseRowSet implements Serializable, Cloneable { } - /** - * Sets the designated parameter to a java.sql.NClob object. The object - * implements the java.sql.NClob interface. This NClob - * object maps to a SQL NCLOB. - * @param parameterName the name of the column to be set - * @param value the parameter value - * @throws SQLException if the driver does not support national - * character sets; if the driver can detect that a data conversion - * error could occur; or if a database access error occurs - * @since 1.6 - */ - public void setNClob(String parameterName, NClob value) throws SQLException{ + /** + * Sets the designated parameter to a java.sql.NClob object. The object + * implements the java.sql.NClob interface. This NClob + * object maps to a SQL NCLOB. + * @param parameterName the name of the column to be set + * @param value the parameter value + * @throws SQLException if the driver does not support national + * character sets; if the driver can detect that a data conversion + * error could occur; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * @since 1.6 + */ + public void setNClob(String parameterName, NClob value) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } - /** - * Sets the designated parameter to a Reader object. The reader must contain * the number - * of characters specified by length otherwise a SQLException will be - * generated when the CallableStatement is executed. - * This method differs from the setCharacterStream (int, Reader, int) method - * because it informs the driver that the parameter value should be sent to - * the server as a NCLOB. When the setCharacterStream method is used, the - * driver may have to do extra work to determine whether the parameter - * data should be send to the server as a LONGNVARCHAR or a NCLOB - * - * @param parameterName the name of the parameter to be set - * @param reader An object that contains the data to set the parameter value to. - * @param length the number of characters in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the length specified is less than zero; - * if the driver does not support national - * character sets; if the driver can detect that a data conversion - * error could occur; if a database access error occurs or - * this method is called on a closed CallableStatement - * @exception SQLFeatureNotSupportedException if the JDBC driver does not support - * this method - * @since 1.6 - */ - public void setNClob(String parameterName, Reader reader, long length) - throws SQLException{ - throw new SQLFeatureNotSupportedException("Feature not supported"); - } + /** + * Sets the designated parameter to a Reader object. The reader must contain + * the number + * of characters specified by length otherwise a SQLException will be + * generated when the CallableStatement is executed. + * This method differs from the setCharacterStream (int, Reader, int) method + * because it informs the driver that the parameter value should be sent to + * the server as a NCLOB. When the setCharacterStream method is used, the + * driver may have to do extra work to determine whether the parameter + * data should be send to the server as a LONGNVARCHAR or a NCLOB + * + * @param parameterName the name of the parameter to be set + * @param reader An object that contains the data to set the parameter value to. + * @param length the number of characters in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter + * marker in the SQL statement; if the length specified is less than zero; + * if the driver does not support national + * character sets; if the driver can detect that a data conversion + * error could occur; if a database access error occurs or + * this method is called on a closed CallableStatement + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.6 + */ + public void setNClob(String parameterName, Reader reader, long length) + throws SQLException{ + throw new SQLFeatureNotSupportedException("Feature not supported"); + } - /** - * Sets the designated parameter to a Reader object. - * This method differs from the setCharacterStream (int, Reader) method - * because it informs the driver that the parameter value should be sent to - * the server as a NCLOB. When the setCharacterStream method is used, the - * driver may have to do extra work to determine whether the parameter - * data should be send to the server as a LONGNVARCHAR or a NCLOB - *

    Note: Consult your JDBC driver documentation to determine if - * it might be more efficient to use a version of - * setNClob which takes a length parameter. - * - * @param parameterName the name of the parameter - * @param reader An object that contains the data to set the parameter value to. - * @throws SQLException if the driver does not support national character sets; - * if the driver can detect that a data conversion - * error could occur; if a database access error occurs or - * this method is called on a closed CallableStatement - * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method - * - * @since 1.6 - */ + /** + * Sets the designated parameter to a Reader object. + * This method differs from the setCharacterStream (int, Reader) method + * because it informs the driver that the parameter value should be sent to + * the server as a NCLOB. When the setCharacterStream method is used, the + * driver may have to do extra work to determine whether the parameter + * data should be send to the server as a LONGNVARCHAR or a NCLOB + *

    Note: Consult your JDBC driver documentation to determine if + * it might be more efficient to use a version of + * setNClob which takes a length parameter. + * + * @param parameterName the name of the parameter + * @param reader An object that contains the data to set the parameter value to. + * @throws SQLException if the driver does not support national character sets; + * if the driver can detect that a data conversion + * error could occur; if a database access error occurs or + * this method is called on a closed CallableStatement + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * + * @since 1.6 + */ public void setNClob(String parameterName, Reader reader) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } - /** - * Sets the designated parameter to a Reader object. The reader must contain the number - * of characters specified by length otherwise a SQLException will be - * generated when the PreparedStatement is executed. - * This method differs from the setCharacterStream (int, Reader, int) method - * because it informs the driver that the parameter value should be sent to - * the server as a NCLOB. When the setCharacterStream method is used, the - * driver may have to do extra work to determine whether the parameter - * data should be sent to the server as a LONGNVARCHAR or a NCLOB - * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param reader An object that contains the data to set the parameter value to. - * @param length the number of characters in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the length specified is less than zero; - * if the driver does not support national character sets; - * if the driver can detect that a data conversion - * error could occur; if a database access error occurs or - * this method is called on a closed PreparedStatement - * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method - * - * @since 1.6 - */ - public void setNClob(int parameterIndex, Reader reader, long length) + /** + * Sets the designated parameter to a Reader object. The reader must contain the number + * of characters specified by length otherwise a SQLException will be + * generated when the PreparedStatement is executed. + * This method differs from the setCharacterStream (int, Reader, int) method + * because it informs the driver that the parameter value should be sent to + * the server as a NCLOB. When the setCharacterStream method is used, the + * driver may have to do extra work to determine whether the parameter + * data should be sent to the server as a LONGNVARCHAR or a NCLOB + * @param parameterIndex index of the first parameter is 1, the second is 2, ... + * @param reader An object that contains the data to set the parameter value to. + * @param length the number of characters in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter + * marker in the SQL statement; if the length specified is less than zero; + * if the driver does not support national character sets; + * if the driver can detect that a data conversion + * error could occur; if a database access error occurs or + * this method is called on a closed PreparedStatement + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * + * @since 1.6 + */ + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } - /** - * Sets the designated parameter to a java.sql.NClob object. The driver converts this oa - * SQL NCLOB value when it sends it to the database. - * @param parameterIndex of the first parameter is 1, the second is 2, ... - * @param value the parameter value - * @throws SQLException if the driver does not support national - * character sets; if the driver can detect that a data conversion - * error could occur ; or if a database access error occurs - * @since 1.6 - */ - public void setNClob(int parameterIndex, NClob value) throws SQLException{ + /** + * Sets the designated parameter to a java.sql.NClob object. The driver converts this oa + * SQL NCLOB value when it sends it to the database. + * @param parameterIndex of the first parameter is 1, the second is 2, ... + * @param value the parameter value + * @throws SQLException if the driver does not support national + * character sets; if the driver can detect that a data conversion + * error could occur ; or if a database access error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not + * support this method + * @since 1.6 + */ + public void setNClob(int parameterIndex, NClob value) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } /** @@ -4486,27 +4508,27 @@ public abstract class BaseRowSet implements Serializable, Cloneable { public void setNClob(int parameterIndex, Reader reader) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } - /** - * Sets the designated parameter to the given java.net.URL value. - * The driver converts this to an SQL DATALINK value - * when it sends it to the database. - * - * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param x the java.net.URL object to be set - * @exception SQLException if a database access error occurs or - * this method is called on a closed PreparedStatement - * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method - * @since 1.4 - */ + /** + * Sets the designated parameter to the given java.net.URL value. + * The driver converts this to an SQL DATALINK value + * when it sends it to the database. + * + * @param parameterIndex the first parameter is 1, the second is 2, ... + * @param x the java.net.URL object to be set + * @exception SQLException if a database access error occurs or + * this method is called on a closed PreparedStatement + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @since 1.4 + */ public void setURL(int parameterIndex, java.net.URL x) throws SQLException{ throw new SQLFeatureNotSupportedException("Feature not supported"); - } + } - static final long serialVersionUID = 4886719666485113312L; + static final long serialVersionUID = 4886719666485113312L; } //end class diff --git a/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java b/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java index f05be51c14f..95a9938a007 100644 --- a/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java @@ -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 @@ -55,6 +55,7 @@ import java.util.Map; * stream to the method SQLData.readSQL, which in turn * calls the SQLInputImpl reader methods * to read the attributes from the input stream. + * @since 1.5 * @see java.sql.SQLData */ public class SQLInputImpl implements SQLInput { @@ -142,6 +143,7 @@ public class SQLInputImpl implements SQLInput { throw new SQLException("SQLInputImpl exception: Invalid read " + "position"); } else { + lastValueWasNull = attrib[idx] == null; return attrib[idx]; } } @@ -168,16 +170,7 @@ public class SQLInputImpl implements SQLInput { * position or if there are no further values in the stream. */ public String readString() throws SQLException { - - String attrib = (String)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (String)getNextAttribute(); } /** @@ -195,16 +188,8 @@ public class SQLInputImpl implements SQLInput { * position or if there are no further values in the stream. */ public boolean readBoolean() throws SQLException { - Boolean attrib = (Boolean)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return false; - } else { - lastValueWasNull = false; - return attrib.booleanValue(); - } + return (attrib == null) ? false : attrib.booleanValue(); } /** @@ -223,14 +208,7 @@ public class SQLInputImpl implements SQLInput { */ public byte readByte() throws SQLException { Byte attrib = (Byte)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return (byte)0; - } else { - lastValueWasNull = false; - return attrib.byteValue(); - } + return (attrib == null) ? 0 : attrib.byteValue(); } /** @@ -248,14 +226,7 @@ public class SQLInputImpl implements SQLInput { */ public short readShort() throws SQLException { Short attrib = (Short)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return (short)0; - } else { - lastValueWasNull = false; - return attrib.shortValue(); - } + return (attrib == null) ? 0 : attrib.shortValue(); } /** @@ -273,14 +244,7 @@ public class SQLInputImpl implements SQLInput { */ public int readInt() throws SQLException { Integer attrib = (Integer)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return 0; - } else { - lastValueWasNull = false; - return attrib.intValue(); - } + return (attrib == null) ? 0 : attrib.intValue(); } /** @@ -298,14 +262,7 @@ public class SQLInputImpl implements SQLInput { */ public long readLong() throws SQLException { Long attrib = (Long)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return (long)0; - } else { - lastValueWasNull = false; - return attrib.longValue(); - } + return (attrib == null) ? 0 : attrib.longValue(); } /** @@ -323,14 +280,7 @@ public class SQLInputImpl implements SQLInput { */ public float readFloat() throws SQLException { Float attrib = (Float)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return (float)0; - } else { - lastValueWasNull = false; - return attrib.floatValue(); - } + return (attrib == null) ? 0 : attrib.floatValue(); } /** @@ -348,14 +298,7 @@ public class SQLInputImpl implements SQLInput { */ public double readDouble() throws SQLException { Double attrib = (Double)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return (double)0; - } else { - lastValueWasNull = false; - return attrib.doubleValue(); - } + return (attrib == null) ? 0 : attrib.doubleValue(); } /** @@ -372,15 +315,7 @@ public class SQLInputImpl implements SQLInput { * position or if there are no more values in the stream */ public java.math.BigDecimal readBigDecimal() throws SQLException { - java.math.BigDecimal attrib = (java.math.BigDecimal)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.math.BigDecimal)getNextAttribute(); } /** @@ -397,15 +332,7 @@ public class SQLInputImpl implements SQLInput { * position or if there are no more values in the stream */ public byte[] readBytes() throws SQLException { - byte[] attrib = (byte[])getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (byte[])getNextAttribute(); } /** @@ -422,15 +349,7 @@ public class SQLInputImpl implements SQLInput { * position or if there are no more values in the stream */ public java.sql.Date readDate() throws SQLException { - java.sql.Date attrib = (java.sql.Date)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.sql.Date)getNextAttribute(); } /** @@ -448,15 +367,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.sql.Time readTime() throws SQLException { - java.sql.Time attrib = (java.sql.Time)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.sql.Time)getNextAttribute(); } /** @@ -469,15 +380,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.sql.Timestamp readTimestamp() throws SQLException { - java.sql.Timestamp attrib = (java.sql.Timestamp)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.sql.Timestamp)getNextAttribute(); } /** @@ -494,15 +397,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.io.Reader readCharacterStream() throws SQLException { - java.io.Reader attrib = (java.io.Reader)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.io.Reader)getNextAttribute(); } /** @@ -520,15 +415,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.io.InputStream readAsciiStream() throws SQLException { - java.io.InputStream attrib = (java.io.InputStream)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.io.InputStream)getNextAttribute(); } /** @@ -546,15 +433,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.io.InputStream readBinaryStream() throws SQLException { - java.io.InputStream attrib = (java.io.InputStream)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (java.io.InputStream)getNextAttribute(); } //================================================================ @@ -589,39 +468,32 @@ public class SQLInputImpl implements SQLInput { */ public Object readObject() throws SQLException { Object attrib = getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - if (attrib instanceof Struct) { - Struct s = (Struct)attrib; - // look up the class in the map - Class c = map.get(s.getSQLTypeName()); - if (c != null) { - // create new instance of the class - SQLData obj = null; - try { - obj = (SQLData)c.newInstance(); - } catch (java.lang.InstantiationException ex) { - throw new SQLException("Unable to instantiate: " + - ex.getMessage()); - } catch (java.lang.IllegalAccessException ex) { - throw new SQLException("Unable to instantiate: " + - ex.getMessage()); - } - // get the attributes from the struct - Object attribs[] = s.getAttributes(map); - // create the SQLInput "stream" - SQLInputImpl sqlInput = new SQLInputImpl(attribs, map); - // read the values... - obj.readSQL(sqlInput, s.getSQLTypeName()); - return obj; + if (attrib instanceof Struct) { + Struct s = (Struct)attrib; + // look up the class in the map + Class c = map.get(s.getSQLTypeName()); + if (c != null) { + // create new instance of the class + SQLData obj = null; + try { + obj = (SQLData)c.newInstance(); + } catch (java.lang.InstantiationException ex) { + throw new SQLException("Unable to instantiate: " + + ex.getMessage()); + } catch (java.lang.IllegalAccessException ex) { + throw new SQLException("Unable to instantiate: " + + ex.getMessage()); } + // get the attributes from the struct + Object attribs[] = s.getAttributes(map); + // create the SQLInput "stream" + SQLInputImpl sqlInput = new SQLInputImpl(attribs, map); + // read the values... + obj.readSQL(sqlInput, s.getSQLTypeName()); + return obj; } - return attrib; } + return attrib; } /** @@ -635,15 +507,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public Ref readRef() throws SQLException { - Ref attrib = (Ref)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (Ref)getNextAttribute(); } /** @@ -664,15 +528,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public Blob readBlob() throws SQLException { - Blob attrib = (Blob)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (Blob)getNextAttribute(); } /** @@ -693,15 +549,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public Clob readClob() throws SQLException { - - Clob attrib = (Clob)getNextAttribute(); - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (Clob)getNextAttribute(); } /** @@ -723,15 +571,7 @@ public class SQLInputImpl implements SQLInput { */ public Array readArray() throws SQLException { - Array attrib = (Array)getNextAttribute(); - - if (attrib == null) { - lastValueWasNull = true; - return null; - } else { - lastValueWasNull = false; - return attrib; - } + return (Array)getNextAttribute(); } /** @@ -766,7 +606,7 @@ public class SQLInputImpl implements SQLInput { * position; or if there are no further values in the stream. */ public java.net.URL readURL() throws SQLException { - throw new SQLException("Operation not supported"); + return (java.net.URL)getNextAttribute(); } //---------------------------- JDBC 4.0 ------------------------- @@ -779,10 +619,11 @@ public class SQLInputImpl implements SQLInput { * at the head of the stream; null if the value read is * SQL NULL * @exception SQLException if a database access error occurs + * @since 1.6 */ public NClob readNClob() throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); - } + return (NClob)getNextAttribute(); + } /** * Reads the next attribute in the stream and returns it as a String @@ -792,9 +633,10 @@ public class SQLInputImpl implements SQLInput { * * @return the attribute; if the value is SQL NULL, returns null * @exception SQLException if a database access error occurs + * @since 1.6 */ public String readNString() throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); + return (String)getNextAttribute(); } /** @@ -805,12 +647,13 @@ public class SQLInputImpl implements SQLInput { * at the head of the stream; null if the value read is * SQL NULL * @exception SQLException if a database access error occurs + * @since 1.6 */ public SQLXML readSQLXML() throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); + return (SQLXML)getNextAttribute(); } - /** + /** * Reads an SQL ROWID value from the stream and returns it as a * RowId object in the Java programming language. * @@ -818,9 +661,10 @@ public class SQLInputImpl implements SQLInput { * at the head of the stream; null if the value read is * SQL NULL * @exception SQLException if a database access error occurs + * @since 1.6 */ public RowId readRowId() throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); + return (RowId)getNextAttribute(); } diff --git a/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java b/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java index fbe4a741726..cf2824cfda9 100644 --- a/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java @@ -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 @@ -579,7 +579,7 @@ public class SQLOutputImpl implements SQLOutput { } - /** + /** * Writes the next attribute to the stream as a String * in the Java programming language. The driver converts this to a * SQL NCHAR or @@ -594,8 +594,8 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeNString(String x) throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); - } + attribs.add(x); + } /** * Writes an SQL NCLOB value to the stream. @@ -608,8 +608,8 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeNClob(NClob x) throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); - } + attribs.add(x); + } /** @@ -623,8 +623,8 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeRowId(RowId x) throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); - } + attribs.add(x); + } /** @@ -638,7 +638,7 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeSQLXML(SQLXML x) throws SQLException { - throw new UnsupportedOperationException("Operation not supported"); + attribs.add(x); } } diff --git a/jdk/src/share/classes/javax/swing/UIManager.java b/jdk/src/share/classes/javax/swing/UIManager.java index d135e34b5c9..17a7b9e81dc 100644 --- a/jdk/src/share/classes/javax/swing/UIManager.java +++ b/jdk/src/share/classes/javax/swing/UIManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -105,8 +105,9 @@ import sun.awt.AWTAccessor; * exists and contains the key swing.defaultlaf, * use its value as the default look and feel class name. The location * that is checked for swing.properties may vary depending - * upon the implementation of the Java platform. In Sun's implementation - * the location is ${java.home}/lib/swing.properties. + * upon the implementation of the Java platform. Typically the + * swing.properties file is located in the lib + * subdirectory of the Java installation directory. * Refer to the release notes of the implementation being used for * further details. *

  • Otherwise use the cross platform look and feel. @@ -256,7 +257,7 @@ public class UIManager implements Serializable } - /* Keys used for the properties file in /lib/swing.properties. + /* Keys used in the swing.properties properties file. * See loadUserProperties(), initialize(). */ @@ -267,7 +268,7 @@ public class UIManager implements Serializable private static final String disableMnemonicKey = "swing.disablenavaids"; /** - * Return a swing.properties file key for the attribute of specified + * Return a swing.properties file key for the attribute of specified * look and feel. The attr is either "name" or "class", a typical * key would be: "swing.installedlaf.windows.name" */ @@ -276,9 +277,11 @@ public class UIManager implements Serializable } /** - * The filename for swing.properties is a path like this (Unix version): - * /lib/swing.properties. This method returns a bogus - * filename if java.home isn't defined. + * The location of the swing.properties property file is + * implementation-specific. + * It is typically located in the lib subdirectory of the Java + * installation directory. This method returns a bogus filename + * if java.home isn't defined. */ private static String makeSwingPropertiesFilename() { String sep = File.separator; @@ -352,7 +355,7 @@ public class UIManager implements Serializable /** * The default value of installedLAFS is used when no - * swing.properties + * swing.properties * file is available or if the file doesn't contain a "swing.installedlafs" * property. * @@ -1271,7 +1274,8 @@ public class UIManager implements Serializable /** - * If a swing.properties file exist and it has a swing.installedlafs property + * If a swing.properties file exist and it has a + * swing.installedlafs property * then initialize the installedLAFs field. * * @see #getInstalledLookAndFeels 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 437704ad4e7..5a9135844bc 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1153,7 +1153,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab "Menu.menuPopupOffsetY", new Integer(0), "Menu.submenuPopupOffsetX", new Integer(0), "Menu.submenuPopupOffsetY", new Integer(0), - "Menu.shortcutKeys", new int[] {KeyEvent.ALT_MASK}, + "Menu.shortcutKeys", new int[]{ + SwingUtilities2.getSystemMnemonicKeyMask() + }, "Menu.crossMenuMnemonic", Boolean.TRUE, // Menu.cancelMode affects the cancel menu action behaviour; // currently supports: diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 497c0d6cac0..3d39cf6a876 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -1879,6 +1879,20 @@ public class BasicTreeUI extends TreeUI visRect.x -= i.left; visRect.y -= i.top; } + // we should consider a non-visible area above + Component component = SwingUtilities.getUnwrappedParent(tree); + if (component instanceof JViewport) { + component = component.getParent(); + if (component instanceof JScrollPane) { + JScrollPane pane = (JScrollPane) component; + JScrollBar bar = pane.getHorizontalScrollBar(); + if ((bar != null) && bar.isVisible()) { + int height = bar.getHeight(); + visRect.y -= height; + visRect.height += height; + } + } + } preferredSize.width = treeState.getPreferredWidth(visRect); } else { @@ -4504,7 +4518,7 @@ public class BasicTreeUI extends TreeUI } } - private void home(JTree tree, BasicTreeUI ui, int direction, + private void home(JTree tree, final BasicTreeUI ui, int direction, boolean addToSelection, boolean changeSelection) { // disable moving of lead unless in discontiguous mode @@ -4514,7 +4528,7 @@ public class BasicTreeUI extends TreeUI changeSelection = true; } - int rowCount = ui.getRowCount(tree); + final int rowCount = ui.getRowCount(tree); if (rowCount > 0) { if(direction == -1) { @@ -4566,6 +4580,13 @@ public class BasicTreeUI extends TreeUI ui.setLeadSelectionPath(ui.getPathForRow(tree, rowCount - 1), true); } + if (ui.isLargeModel()){ + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ui.ensureRowsAreVisible(rowCount - 1, rowCount - 1); + } + }); + } } } } diff --git a/jdk/src/share/classes/sun/awt/image/SurfaceManager.java b/jdk/src/share/classes/sun/awt/image/SurfaceManager.java index 9451f91e323..f10673a9423 100644 --- a/jdk/src/share/classes/sun/awt/image/SurfaceManager.java +++ b/jdk/src/share/classes/sun/awt/image/SurfaceManager.java @@ -88,7 +88,7 @@ public abstract class SurfaceManager { imgaccessor.setSurfaceManager(img, mgr); } - private ConcurrentHashMap cacheMap; + private ConcurrentHashMap cacheMap; /** * Return an arbitrary cached object for an arbitrary cache key. @@ -123,7 +123,7 @@ public abstract class SurfaceManager { if (cacheMap == null) { synchronized (this) { if (cacheMap == null) { - cacheMap = new ConcurrentHashMap(2); + cacheMap = new ConcurrentHashMap<>(2); } } } @@ -245,7 +245,7 @@ public abstract class SurfaceManager { synchronized void flush(boolean deaccelerate) { if (cacheMap != null) { - Iterator i = cacheMap.values().iterator(); + Iterator i = cacheMap.values().iterator(); while (i.hasNext()) { Object o = i.next(); if (o instanceof FlushableCacheData) { diff --git a/jdk/src/share/classes/sun/misc/Contended.java b/jdk/src/share/classes/sun/misc/Contended.java new file mode 100644 index 00000000000..6925b4242d6 --- /dev/null +++ b/jdk/src/share/classes/sun/misc/Contended.java @@ -0,0 +1,45 @@ +/* + * 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.misc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation marks classes and fields as considered to be contended. + * @since 1.8 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.TYPE}) +public @interface Contended { + + /** + Defines the contention group tag. + */ + String value() default ""; +} diff --git a/jdk/src/share/classes/sun/misc/FloatingDecimal.java b/jdk/src/share/classes/sun/misc/FloatingDecimal.java index 2679a4eec3f..2db646d2cc1 100644 --- a/jdk/src/share/classes/sun/misc/FloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -41,6 +41,19 @@ public class FloatingDecimal{ boolean fromHex = false; int roundDir = 0; // set by doubleValue + /* + * The fields below provides additional information about the result of + * the binary to decimal digits conversion done in dtoa() and roundup() + * methods. They are changed if needed by those two methods. + */ + + // True if the dtoa() binary to decimal conversion was exact. + boolean exactDecimalConversion = false; + + // True if the result of the binary to decimal conversion was rounded-up + // at the end of the conversion process, i.e. roundUp() method was called. + boolean decimalDigitsRoundedUp = false; + private FloatingDecimal( boolean negSign, int decExponent, char []digits, int n, boolean e ) { isNegative = negSign; @@ -396,6 +409,11 @@ public class FloatingDecimal{ // else fall through. } digits[i] = (char)(q+1); + decimalDigitsRoundedUp = true; + } + + public boolean digitsRoundedUp() { + return decimalDigitsRoundedUp; } /* @@ -751,6 +769,7 @@ public class FloatingDecimal{ digits[ndigit++] = (char)('0' + q); } lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); } else { // still good! they're all longs! long b = (fractBits * long5pow[B5] ) << B2; @@ -804,8 +823,10 @@ public class FloatingDecimal{ digits[ndigit++] = (char)('0' + q); } lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); } } else { + FDBigInt ZeroVal = new FDBigInt(0); FDBigInt tenSval; int shiftBias; @@ -859,8 +880,10 @@ public class FloatingDecimal{ if ( high && low ){ Bval.lshiftMe(1); lowDigitDifference = Bval.cmp(tenSval); - } else + } else { lowDigitDifference = 0L; // this here only for flow analysis! + } + exactDecimalConversion = (Bval.cmp( ZeroVal ) == 0); } this.decExponent = decExp+1; this.digits = digits; @@ -883,6 +906,10 @@ public class FloatingDecimal{ } } + public boolean decimalDigitsExact() { + return exactDecimalConversion; + } + public String toString(){ // most brain-dead version diff --git a/jdk/src/share/classes/sun/misc/URLClassPath.java b/jdk/src/share/classes/sun/misc/URLClassPath.java index eb6b86aecbd..40567231267 100644 --- a/jdk/src/share/classes/sun/misc/URLClassPath.java +++ b/jdk/src/share/classes/sun/misc/URLClassPath.java @@ -508,7 +508,8 @@ public class URLClassPath { } } else { // our best guess for the other cases - InputStream is = url.openStream(); + uc.setUseCaches(false); + InputStream is = uc.getInputStream(); is.close(); } return url; diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java index 706037223fd..2cc087f8233 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java @@ -31,8 +31,8 @@ import java.net.URISyntaxException; import java.net.PasswordAuthentication; import java.io.IOException; import java.io.OutputStream; +import java.util.Base64; import sun.net.www.HeaderParser; -import sun.misc.BASE64Encoder; /** * BasicAuthentication: Encapsulate an http server authentication using @@ -76,7 +76,7 @@ class BasicAuthentication extends AuthenticationInfo { System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length); System.arraycopy(passwdBytes, 0, concat, nameBytes.length, passwdBytes.length); - this.auth = "Basic " + (new BasicBASE64Encoder()).encode(concat); + this.auth = "Basic " + Base64.getEncoder().encodeToString(concat); this.pw = pw; } @@ -116,7 +116,7 @@ class BasicAuthentication extends AuthenticationInfo { System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length); System.arraycopy(passwdBytes, 0, concat, nameBytes.length, passwdBytes.length); - this.auth = "Basic " + (new BasicBASE64Encoder()).encode(concat); + this.auth = "Basic " + Base64.getEncoder().encodeToString(concat); this.pw = pw; } @@ -201,12 +201,5 @@ class BasicAuthentication extends AuthenticationInfo { /*should not reach here. If we do simply return npath*/ return npath; } - - /* It is never expected that the header value will exceed the bytesPerLine */ - private class BasicBASE64Encoder extends BASE64Encoder { - @Override - protected int bytesPerLine() { - return (10000); - } - } } + diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java index 23a8a83ca94..24e99044c42 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java @@ -28,10 +28,9 @@ package sun.net.www.protocol.http; import java.net.URL; import java.io.IOException; import java.net.Authenticator.RequestorType; +import java.util.Base64; import java.util.HashMap; import sun.net.www.HeaderParser; -import sun.misc.BASE64Decoder; -import sun.misc.BASE64Encoder; import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE; import static sun.net.www.protocol.http.AuthScheme.KERBEROS; @@ -151,9 +150,9 @@ class NegotiateAuthentication extends AuthenticationInfo { byte[] incoming = null; String[] parts = raw.split("\\s+"); if (parts.length > 1) { - incoming = new BASE64Decoder().decodeBuffer(parts[1]); + incoming = Base64.getDecoder().decode(parts[1]); } - response = hci.scheme + " " + new B64Encoder().encode( + response = hci.scheme + " " + Base64.getEncoder().encodeToString( incoming==null?firstToken():nextToken(incoming)); conn.setAuthenticationProperty(getHeaderName(), response); @@ -201,12 +200,6 @@ class NegotiateAuthentication extends AuthenticationInfo { return negotiator.nextToken(token); } - class B64Encoder extends BASE64Encoder { - protected int bytesPerLine () { - return 100000; // as big as it can be, maybe INT_MAX - } - } - // MS will send a final WWW-Authenticate even if the status is already // 200 OK. The token can be fed into initSecContext() again to determine // if the server can be trusted. This is not the same concept as Digest's diff --git a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java index 7da5c12e70c..559f7e1cea8 100644 --- a/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/jdk/src/share/classes/sun/nio/cs/ISO_8859_1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, 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 @@ -147,37 +147,53 @@ class ISO_8859_1 private final Surrogate.Parser sgp = new Surrogate.Parser(); + // JVM may replace this method with intrinsic code. + private static int encodeISOArray(char[] sa, int sp, + byte[] da, int dp, int len) + { + int i = 0; + for (; i < len; i++) { + char c = sa[sp++]; + if (c > '\u00FF') + break; + da[dp++] = (byte)c; + } + return i; + } + private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); + int soff = src.arrayOffset(); + int sp = soff + src.position(); + int sl = soff + src.limit(); assert (sp <= sl); sp = (sp <= sl ? sp : sl); byte[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); + int doff = dst.arrayOffset(); + int dp = doff + dst.position(); + int dl = doff + dst.limit(); assert (dp <= dl); dp = (dp <= dl ? dp : dl); + int dlen = dl - dp; + int slen = sl - sp; + int len = (dlen < slen) ? dlen : slen; try { - while (sp < sl) { - char c = sa[sp]; - if (c <= '\u00FF') { - if (dp >= dl) - return CoderResult.OVERFLOW; - da[dp++] = (byte)c; - sp++; - continue; - } - if (sgp.parse(c, sa, sp, sl) < 0) + int ret = encodeISOArray(sa, sp, da, dp, len); + sp = sp + ret; + dp = dp + ret; + if (ret != len) { + if (sgp.parse(sa[sp], sa, sp, sl) < 0) return sgp.error(); return sgp.unmappableResult(); } + if (len < slen) + return CoderResult.OVERFLOW; return CoderResult.UNDERFLOW; } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); + src.position(sp - soff); + dst.position(dp - doff); } } @@ -221,22 +237,25 @@ class ISO_8859_1 public int encode(char[] src, int sp, int len, byte[] dst) { int dp = 0; - int sl = sp + Math.min(len, dst.length); + int slen = Math.min(len, dst.length); + int sl = sp + slen; while (sp < sl) { - char c = src[sp++]; - if (c <= '\u00FF') { - dst[dp++] = (byte)c; - continue; - } - if (Character.isHighSurrogate(c) && sp < sl && - Character.isLowSurrogate(src[sp])) { - if (len > dst.length) { - sl++; - len--; + int ret = encodeISOArray(src, sp, dst, dp, slen); + sp = sp + ret; + dp = dp + ret; + if (ret != slen) { + char c = src[sp++]; + if (Character.isHighSurrogate(c) && sp < sl && + Character.isLowSurrogate(src[sp])) { + if (len > dst.length) { + sl++; + len--; + } + sp++; } - sp++; + dst[dp++] = repl; + slen = Math.min((sl - sp), (dst.length - dp)); } - dst[dp++] = repl; } return dp; } diff --git a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 69ac4d6f7e3..eefdbff811f 100644 --- a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -26,31 +26,42 @@ package sun.security.pkcs12; import java.io.*; +import java.security.AccessController; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Key; import java.security.KeyFactory; -import java.security.PrivateKey; +import java.security.KeyStore; import java.security.KeyStoreSpi; import java.security.KeyStoreException; +import java.security.PKCS12Attribute; +import java.security.PrivateKey; +import java.security.PrivilegedAction; +import java.security.UnrecoverableEntryException; import java.security.UnrecoverableKeyException; import java.security.SecureRandom; +import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.util.*; import java.security.AlgorithmParameters; import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKey; import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.security.auth.DestroyFailedException; import javax.security.auth.x500.X500Principal; +import sun.security.util.Debug; import sun.security.util.DerInputStream; import sun.security.util.DerOutputStream; import sun.security.util.DerValue; @@ -99,11 +110,12 @@ import sun.security.pkcs.EncryptedPrivateKeyInfo; * OpenSSL PKCS#12 code. All. All. * --------------------------------------------------------------------- * - * NOTE: Currently PKCS12 KeyStore does not support TrustedCertEntries. + * NOTE: PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry. * PKCS#12 is mainly used to deliver private keys with their associated * certificate chain and aliases. In a PKCS12 keystore, entries are * identified by the alias, and a localKeyId is required to match the - * private key with the certificate. + * private key with the certificate. Trusted certificate entries are identified + * by the presence of an trustedKeyUsage attribute. * * @author Seema Malkani * @author Jeff Nisewanger @@ -119,8 +131,23 @@ public final class PKCS12KeyStore extends KeyStoreSpi { public static final int VERSION_3 = 3; + private static final String[] KEY_PROTECTION_ALGORITHM = { + "keystore.pkcs12.keyProtectionAlgorithm", + "keystore.PKCS12.keyProtectionAlgorithm" + }; + + // friendlyName, localKeyId, trustedKeyUsage + private static final String[] CORE_ATTRIBUTES = { + "1.2.840.113549.1.9.20", + "1.2.840.113549.1.9.21", + "2.16.840.1.113894.746875.1.1" + }; + + private static final Debug debug = Debug.getInstance("pkcs12"); + private static final int keyBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 2}; private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3}; + private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5}; private static final int pkcs9Name[] = {1, 2, 840, 113549, 1, 9, 20}; private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21}; @@ -131,14 +158,27 @@ public final class PKCS12KeyStore extends KeyStoreSpi { {1, 2, 840, 113549, 1, 12, 1, 6}; private static final int pbeWithSHAAnd3KeyTripleDESCBC[] = {1, 2, 840, 113549, 1, 12, 1, 3}; + private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13}; + // TODO: temporary Oracle OID + /* + * { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894) + * jdk(746875) crypto(1) id-at-trustedKeyUsage(1) } + */ + private static final int TrustedKeyUsage[] = + {2, 16, 840, 1, 113894, 746875, 1, 1}; + private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0}; private static ObjectIdentifier PKCS8ShroudedKeyBag_OID; private static ObjectIdentifier CertBag_OID; + private static ObjectIdentifier SecretBag_OID; private static ObjectIdentifier PKCS9FriendlyName_OID; private static ObjectIdentifier PKCS9LocalKeyId_OID; private static ObjectIdentifier PKCS9CertType_OID; private static ObjectIdentifier pbeWithSHAAnd40BitRC2CBC_OID; private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID; + private static ObjectIdentifier pbes2_OID; + private static ObjectIdentifier TrustedKeyUsage_OID; + private static ObjectIdentifier[] AnyUsage; private int counter = 0; private static final int iterationCount = 1024; @@ -149,6 +189,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // in pkcs12 with one private key entry and associated cert-chain private int privateKeyCount = 0; + // secret key count + private int secretKeyCount = 0; + + // certificate count + private int certificateCount = 0; + // the source of randomness private SecureRandom random; @@ -156,6 +202,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { try { PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag); CertBag_OID = new ObjectIdentifier(certBag); + SecretBag_OID = new ObjectIdentifier(secretBag); PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name); PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId); PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType); @@ -163,38 +210,68 @@ public final class PKCS12KeyStore extends KeyStoreSpi { new ObjectIdentifier(pbeWithSHAAnd40BitRC2CBC); pbeWithSHAAnd3KeyTripleDESCBC_OID = new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC); + pbes2_OID = new ObjectIdentifier(pbes2); + TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage); + AnyUsage = new ObjectIdentifier[]{ + new ObjectIdentifier(AnyExtendedKeyUsage)}; } catch (IOException ioe) { // should not happen } } - // Private keys and their supporting certificate chains - private static class KeyEntry { + // A keystore entry and associated attributes + private static class Entry { Date date; // the creation date of this entry + String alias; + byte[] keyId; + Set attributes; + } + + // A key entry + private static class KeyEntry extends Entry { + } + + // A private key entry and its supporting certificate chain + private static class PrivateKeyEntry extends KeyEntry { byte[] protectedPrivKey; Certificate chain[]; - byte[] keyId; - String alias; }; - // A certificate with its PKCS #9 attributes - private static class CertEntry { + // A secret key + private static class SecretKeyEntry extends KeyEntry { + byte[] protectedSecretKey; + }; + + // A certificate entry + private static class CertEntry extends Entry { final X509Certificate cert; - final byte[] keyId; - final String alias; + ObjectIdentifier[] trustedKeyUsage; + CertEntry(X509Certificate cert, byte[] keyId, String alias) { + this(cert, keyId, alias, null, null); + } + + CertEntry(X509Certificate cert, byte[] keyId, String alias, + ObjectIdentifier[] trustedKeyUsage, + Set attributes) { + this.date = new Date(); this.cert = cert; this.keyId = keyId; this.alias = alias; + this.trustedKeyUsage = trustedKeyUsage; + this.attributes = new HashSet<>(); + if (attributes != null) { + this.attributes.addAll(attributes); + } } } /** - * Private keys and certificates are stored in a hashtable. - * Hash entries are keyed by alias names. + * Private keys and certificates are stored in a map. + * Map entries are keyed by alias names. */ - private Hashtable entries = - new Hashtable(); + private Map entries = + Collections.synchronizedMap(new LinkedHashMap()); private ArrayList keyList = new ArrayList(); private LinkedHashMap certsMap = @@ -219,15 +296,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi { public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); Key key = null; - if (entry == null) { + if (entry == null || (!(entry instanceof KeyEntry))) { return null; } - // get the encoded private key - byte[] encrBytes = entry.protectedPrivKey; + // get the encoded private key or secret key + byte[] encrBytes = null; + if (entry instanceof PrivateKeyEntry) { + encrBytes = ((PrivateKeyEntry) entry).protectedPrivKey; + } else if (entry instanceof SecretKeyEntry) { + encrBytes = ((SecretKeyEntry) entry).protectedSecretKey; + } else { + throw new UnrecoverableKeyException("Error locating key"); + } byte[] encryptedKey; AlgorithmParameters algParams; @@ -253,14 +337,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } try { - byte[] privateKeyInfo; + byte[] keyInfo; while (true) { try { // Use JCE SecretKey skey = getPBEKey(password); Cipher cipher = Cipher.getInstance(algOid.toString()); cipher.init(Cipher.DECRYPT_MODE, skey, algParams); - privateKeyInfo = cipher.doFinal(encryptedKey); + keyInfo = cipher.doFinal(encryptedKey); break; } catch (Exception e) { if (password.length == 0) { @@ -273,21 +357,52 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } } - PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(privateKeyInfo); - /* * Parse the key algorithm and then use a JCA key factory - * to create the private key. + * to re-create the key. */ - DerValue val = new DerValue(privateKeyInfo); + DerValue val = new DerValue(keyInfo); DerInputStream in = val.toDerInputStream(); int i = in.getInteger(); DerValue[] value = in.getSequence(2); AlgorithmId algId = new AlgorithmId(value[0].getOID()); - String algName = algId.getName(); + String keyAlgo = algId.getName(); - KeyFactory kfac = KeyFactory.getInstance(algName); - key = kfac.generatePrivate(kspec); + // decode private key + if (entry instanceof PrivateKeyEntry) { + KeyFactory kfac = KeyFactory.getInstance(keyAlgo); + PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo); + key = kfac.generatePrivate(kspec); + + if (debug != null) { + debug.println("Retrieved a protected private key (" + + key.getClass().getName() + ") at alias '" + alias + + "'"); + } + + // decode secret key + } else { + SecretKeyFactory sKeyFactory = + SecretKeyFactory.getInstance(keyAlgo); + byte[] keyBytes = in.getOctetString(); + SecretKeySpec secretKeySpec = + new SecretKeySpec(keyBytes, keyAlgo); + + // Special handling required for PBE: needs a PBEKeySpec + if (keyAlgo.startsWith("PBE")) { + KeySpec pbeKeySpec = + sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class); + key = sKeyFactory.generateSecret(pbeKeySpec); + } else { + key = sKeyFactory.generateSecret(secretKeySpec); + } + + if (debug != null) { + debug.println("Retrieved a protected secret key (" + + key.getClass().getName() + ") at alias '" + alias + + "'"); + } + } } catch (Exception e) { UnrecoverableKeyException uke = new UnrecoverableKeyException("Get Key failed: " + @@ -310,12 +425,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * key entry without a certificate chain). */ public Certificate[] engineGetCertificateChain(String alias) { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); - if (entry != null) { - if (entry.chain == null) { + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry != null && entry instanceof PrivateKeyEntry) { + if (((PrivateKeyEntry) entry).chain == null) { return null; } else { - return entry.chain.clone(); + + if (debug != null) { + debug.println("Retrieved a " + + ((PrivateKeyEntry) entry).chain.length + + "-certificate chain at alias '" + alias + "'"); + } + + return ((PrivateKeyEntry) entry).chain.clone(); } } else { return null; @@ -338,13 +460,39 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * does not contain a certificate. */ public Certificate engineGetCertificate(String alias) { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); - if (entry != null) { - if (entry.chain == null) { + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry == null) { + return null; + } + if (entry instanceof CertEntry && + ((CertEntry) entry).trustedKeyUsage != null) { + + if (debug != null) { + if (Arrays.equals(AnyUsage, + ((CertEntry) entry).trustedKeyUsage)) { + debug.println("Retrieved a certificate at alias '" + alias + + "' (trusted for any purpose)"); + } else { + debug.println("Retrieved a certificate at alias '" + alias + + "' (trusted for limited purposes)"); + } + } + + return ((CertEntry) entry).cert; + + } else if (entry instanceof PrivateKeyEntry) { + if (((PrivateKeyEntry) entry).chain == null) { return null; } else { - return entry.chain[0]; + + if (debug != null) { + debug.println("Retrieved a certificate at alias '" + alias + + "'"); + } + + return ((PrivateKeyEntry) entry).chain[0]; } + } else { return null; } @@ -359,7 +507,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * not exist */ public Date engineGetCreationDate(String alias) { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); if (entry != null) { return new Date(entry.date.getTime()); } else { @@ -393,40 +541,110 @@ public final class PKCS12KeyStore extends KeyStoreSpi { char[] password, Certificate[] chain) throws KeyStoreException { + KeyStore.PasswordProtection passwordProtection = + new KeyStore.PasswordProtection(password); + try { - KeyEntry entry = new KeyEntry(); - entry.date = new Date(); + setKeyEntry(alias, key, passwordProtection, chain, null); + + } finally { + try { + passwordProtection.destroy(); + } catch (DestroyFailedException dfe) { + // ignore + } + } + } + + /* + * Sets a key entry (with attributes, when present) + */ + private void setKeyEntry(String alias, Key key, + KeyStore.PasswordProtection passwordProtection, Certificate[] chain, + Set attributes) + throws KeyStoreException + { + try { + Entry entry; if (key instanceof PrivateKey) { + PrivateKeyEntry keyEntry = new PrivateKeyEntry(); + keyEntry.date = new Date(); + if ((key.getFormat().equals("PKCS#8")) || (key.getFormat().equals("PKCS8"))) { + + if (debug != null) { + debug.println("Setting a protected private key (" + + key.getClass().getName() + ") at alias '" + alias + + "'"); + } + // Encrypt the private key - entry.protectedPrivKey = - encryptPrivateKey(key.getEncoded(), password); + keyEntry.protectedPrivKey = + encryptPrivateKey(key.getEncoded(), passwordProtection); } else { throw new KeyStoreException("Private key is not encoded" + "as PKCS#8"); } + + // clone the chain + if (chain != null) { + // validate cert-chain + if ((chain.length > 1) && (!validateChain(chain))) + throw new KeyStoreException("Certificate chain is " + + "not valid"); + keyEntry.chain = chain.clone(); + certificateCount += chain.length; + + if (debug != null) { + debug.println("Setting a " + chain.length + + "-certificate chain at alias '" + alias + "'"); + } + } + privateKeyCount++; + entry = keyEntry; + + } else if (key instanceof SecretKey) { + SecretKeyEntry keyEntry = new SecretKeyEntry(); + keyEntry.date = new Date(); + + // Encode secret key in a PKCS#8 + DerOutputStream pkcs8 = new DerOutputStream(); + DerOutputStream secretKeyInfo = new DerOutputStream(); + secretKeyInfo.putInteger(0); + AlgorithmId algId = AlgorithmId.get(key.getAlgorithm()); + algId.encode(secretKeyInfo); + secretKeyInfo.putOctetString(key.getEncoded()); + pkcs8.write(DerValue.tag_Sequence, secretKeyInfo); + + // Encrypt the secret key (using same PBE as for private keys) + keyEntry.protectedSecretKey = + encryptPrivateKey(pkcs8.toByteArray(), passwordProtection); + + if (debug != null) { + debug.println("Setting a protected secret key (" + + key.getClass().getName() + ") at alias '" + alias + + "'"); + } + secretKeyCount++; + entry = keyEntry; + } else { - throw new KeyStoreException("Key is not a PrivateKey"); + throw new KeyStoreException("Unsupported Key type"); } - // clone the chain - if (chain != null) { - // validate cert-chain - if ((chain.length > 1) && (!validateChain(chain))) - throw new KeyStoreException("Certificate chain is " + - "not validate"); - entry.chain = chain.clone(); + entry.attributes = new HashSet<>(); + if (attributes != null) { + entry.attributes.addAll(attributes); } - // set the keyId to current date entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8"); // set the alias entry.alias = alias.toLowerCase(Locale.ENGLISH); - // add the entry entries.put(alias.toLowerCase(Locale.ENGLISH), entry); + } catch (Exception nsae) { throw new KeyStoreException("Key protection " + " algorithm not found: " + nsae, nsae); @@ -460,7 +678,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { Certificate[] chain) throws KeyStoreException { - // key must be encoded as EncryptedPrivateKeyInfo + // Private key must be encoded as EncryptedPrivateKeyInfo // as defined in PKCS#8 try { new EncryptedPrivateKeyInfo(key); @@ -469,9 +687,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi { + " as PKCS#8 EncryptedPrivateKeyInfo: " + ioe, ioe); } - KeyEntry entry = new KeyEntry(); + PrivateKeyEntry entry = new PrivateKeyEntry(); entry.date = new Date(); + if (debug != null) { + debug.println("Setting a protected private key at alias '" + + alias + "'"); + } + try { // set the keyId to current date entry.keyId = ("Time " + (entry.date).getTime()).getBytes("UTF8"); @@ -483,10 +706,17 @@ public final class PKCS12KeyStore extends KeyStoreSpi { entry.protectedPrivKey = key.clone(); if (chain != null) { - entry.chain = chain.clone(); + entry.chain = chain.clone(); + certificateCount += chain.length; + + if (debug != null) { + debug.println("Setting a " + entry.chain.length + + "-certificate chain at alias '" + alias + "'"); + } } // add the entry + privateKeyCount++; entries.put(alias.toLowerCase(Locale.ENGLISH), entry); } @@ -565,6 +795,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { PBEKeySpec keySpec = new PBEKeySpec(password); SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE"); skey = skFac.generateSecret(keySpec); + keySpec.clearPassword(); } catch (Exception e) { throw new IOException("getSecretKey failed: " + e.getMessage(), e); @@ -576,31 +807,76 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * Encrypt private key using Password-based encryption (PBE) * as defined in PKCS#5. * - * NOTE: Currently pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is + * NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is * used to derive the key and IV. * * @return encrypted private key encoded as EncryptedPrivateKeyInfo */ - private byte[] encryptPrivateKey(byte[] data, char[] password) + private byte[] encryptPrivateKey(byte[] data, + KeyStore.PasswordProtection passwordProtection) throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException { byte[] key = null; try { - // create AlgorithmParameters - AlgorithmParameters algParams = - getAlgorithmParameters("PBEWithSHA1AndDESede"); + String algorithm; + AlgorithmParameters algParams; + AlgorithmId algid; + + // Initialize PBE algorithm and parameters + algorithm = passwordProtection.getProtectionAlgorithm(); + if (algorithm != null) { + AlgorithmParameterSpec algParamSpec = + passwordProtection.getProtectionParameters(); + if (algParamSpec != null) { + algParams = AlgorithmParameters.getInstance(algorithm); + algParams.init(algParamSpec); + } 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( + new PrivilegedAction() { + public String run() { + String prop = + Security.getProperty( + KEY_PROTECTION_ALGORITHM[0]); + if (prop == null) { + prop = Security.getProperty( + KEY_PROTECTION_ALGORITHM[1]); + } + return prop; + } + }); + if (algorithm == null) { + algorithm = "PBEWithSHA1AndDESede"; + } + algParams = getAlgorithmParameters(algorithm); + algid = new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, + algParams); + } // Use JCE - SecretKey skey = getPBEKey(password); - Cipher cipher = Cipher.getInstance("PBEWithSHA1AndDESede"); + SecretKey skey = getPBEKey(passwordProtection.getPassword()); + Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); byte[] encryptedKey = cipher.doFinal(data); + if (debug != null) { + debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() + + ")"); + } + // wrap encrypted private key in EncryptedPrivateKeyInfo // as defined in PKCS#8 - AlgorithmId algid = - new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, algParams); EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(algid, encryptedKey); key = encrInfo.getEncoded(); @@ -615,6 +891,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { return key; } + /* + * Map a PBE algorithm name onto its object identifier + */ + private ObjectIdentifier mapPBEAlgorithmToOID(String algorithm) + throws NoSuchAlgorithmException { + // Check for PBES2 algorithms + if (algorithm.toLowerCase().startsWith("pbewithhmacsha")) { + return pbes2_OID; + } + return AlgorithmId.get(algorithm).getOID(); + } + /** * Assigns the given certificate to the given alias. * @@ -626,17 +914,36 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * @param cert the certificate * * @exception KeyStoreException if the given alias already exists and does - * identify a key entry, or on an attempt to create a - * trusted cert entry which is currently not supported. + * not identify a trusted certificate entry, or this operation fails + * for some other reason. */ public synchronized void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); - if (entry != null) { + setCertEntry(alias, cert, null); + } + + /* + * Sets a trusted cert entry (with attributes, when present) + */ + private void setCertEntry(String alias, Certificate cert, + Set attributes) throws KeyStoreException { + + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry != null && entry instanceof KeyEntry) { throw new KeyStoreException("Cannot overwrite own certificate"); - } else - throw new KeyStoreException("TrustedCertEntry not supported"); + } + + CertEntry certEntry = + new CertEntry((X509Certificate) cert, null, alias, AnyUsage, + attributes); + certificateCount++; + entries.put(alias, certEntry); + + if (debug != null) { + debug.println("Setting a trusted certificate at alias '" + alias + + "'"); + } } /** @@ -649,6 +956,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi { public synchronized void engineDeleteEntry(String alias) throws KeyStoreException { + if (debug != null) { + debug.println("Removing entry at alias '" + alias + "'"); + } + + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry instanceof PrivateKeyEntry) { + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + if (keyEntry.chain != null) { + certificateCount -= keyEntry.chain.length; + } + privateKeyCount--; + } else if (entry instanceof CertEntry) { + certificateCount--; + } else if (entry instanceof SecretKeyEntry) { + secretKeyCount--; + } entries.remove(alias.toLowerCase(Locale.ENGLISH)); } @@ -658,7 +981,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * @return enumeration of the alias names */ public Enumeration engineAliases() { - return entries.keys(); + return Collections.enumeration(entries.keySet()); } /** @@ -689,8 +1012,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * key entry, false otherwise. */ public boolean engineIsKeyEntry(String alias) { - KeyEntry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); - if (entry != null) { + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry != null && entry instanceof KeyEntry) { return true; } else { return false; @@ -705,8 +1028,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * trusted certificate entry, false otherwise. */ public boolean engineIsCertificateEntry(String alias) { - // TrustedCertEntry is not supported - return false; + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (entry != null && entry instanceof CertEntry && + ((CertEntry) entry).trustedKeyUsage != null) { + return true; + } else { + return false; + } } /** @@ -728,11 +1056,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { public String engineGetCertificateAlias(Certificate cert) { Certificate certElem = null; - for (Enumeration e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration e = engineAliases(); e.hasMoreElements(); ) { String alias = e.nextElement(); - KeyEntry entry = entries.get(alias); - if (entry.chain != null) { - certElem = entry.chain[0]; + Entry entry = entries.get(alias); + if (entry instanceof PrivateKeyEntry) { + if (((PrivateKeyEntry) entry).chain != null) { + certElem = ((PrivateKeyEntry) entry).chain[0]; + } + } else if (entry instanceof CertEntry && + ((CertEntry) entry).trustedKeyUsage != null) { + certElem = ((CertEntry) entry).cert; + } else { + continue; } if (certElem.equals(cert)) { return alias; @@ -778,16 +1113,32 @@ public final class PKCS12KeyStore extends KeyStoreSpi { DerOutputStream authSafeContentInfo = new DerOutputStream(); // -- create safeContent Data ContentInfo - byte[] safeContentData = createSafeContent(); - ContentInfo dataContentInfo = new ContentInfo(safeContentData); - dataContentInfo.encode(authSafeContentInfo); + if (privateKeyCount > 0 || secretKeyCount > 0) { + + if (debug != null) { + debug.println("Storing " + privateKeyCount + + " protected key(s) in a PKCS#7 data content-type"); + } + + byte[] safeContentData = createSafeContent(); + ContentInfo dataContentInfo = new ContentInfo(safeContentData); + dataContentInfo.encode(authSafeContentInfo); + } // -- create EncryptedContentInfo - byte[] encrData = createEncryptedData(password); - ContentInfo encrContentInfo = + if (certificateCount > 0) { + + if (debug != null) { + debug.println("Storing " + certificateCount + + " certificate(s) in a PKCS#7 encryptedData content-type"); + } + + byte[] encrData = createEncryptedData(password); + ContentInfo encrContentInfo = new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID, new DerValue(encrData)); - encrContentInfo.encode(authSafeContentInfo); + encrContentInfo.encode(authSafeContentInfo); + } // wrap as SequenceOf ContentInfos DerOutputStream cInfo = new DerOutputStream(); @@ -812,6 +1163,206 @@ public final class PKCS12KeyStore extends KeyStoreSpi { stream.flush(); } + /** + * Gets a KeyStore.Entry for the specified alias + * with the specified protection parameter. + * + * @param alias get the KeyStore.Entry for this alias + * @param protParam the ProtectionParameter + * used to protect the Entry, + * which may be null + * + * @return the KeyStore.Entry for the specified alias, + * or null if there is no such entry + * + * @exception KeyStoreException if the operation failed + * @exception NoSuchAlgorithmException if the algorithm for recovering the + * entry cannot be found + * @exception UnrecoverableEntryException if the specified + * protParam were insufficient or invalid + * @exception UnrecoverableKeyException if the entry is a + * PrivateKeyEntry or SecretKeyEntry + * and the specified protParam does not contain + * the information needed to recover the key (e.g. wrong password) + * + * @since 1.5 + */ + @Override + public KeyStore.Entry engineGetEntry(String alias, + KeyStore.ProtectionParameter protParam) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableEntryException { + + if (!engineContainsAlias(alias)) { + return null; + } + + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + if (protParam == null) { + if (engineIsCertificateEntry(alias)) { + if (entry instanceof CertEntry && + ((CertEntry) entry).trustedKeyUsage != null) { + + if (debug != null) { + debug.println("Retrieved a trusted certificate at " + + "alias '" + alias + "'"); + } + + return new KeyStore.TrustedCertificateEntry( + ((CertEntry)entry).cert, getAttributes(entry)); + } + } else { + throw new UnrecoverableKeyException + ("requested entry requires a password"); + } + } + + if (protParam instanceof KeyStore.PasswordProtection) { + if (engineIsCertificateEntry(alias)) { + throw new UnsupportedOperationException + ("trusted certificate entries are not password-protected"); + } else if (engineIsKeyEntry(alias)) { + KeyStore.PasswordProtection pp = + (KeyStore.PasswordProtection)protParam; + char[] password = pp.getPassword(); + + Key key = engineGetKey(alias, password); + if (key instanceof PrivateKey) { + Certificate[] chain = engineGetCertificateChain(alias); + + return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain, + getAttributes(entry)); + + } else if (key instanceof SecretKey) { + + return new KeyStore.SecretKeyEntry((SecretKey)key, + getAttributes(entry)); + } + } else if (!engineIsKeyEntry(alias)) { + throw new UnsupportedOperationException + ("untrusted certificate entries are not " + + "password-protected"); + } + } + + throw new UnsupportedOperationException(); + } + + /** + * Saves a KeyStore.Entry under the specified alias. + * The specified protection parameter is used to protect the + * Entry. + * + *

    If an entry already exists for the specified alias, + * it is overridden. + * + * @param alias save the KeyStore.Entry under this alias + * @param entry the Entry to save + * @param protParam the ProtectionParameter + * used to protect the Entry, + * which may be null + * + * @exception KeyStoreException if this operation fails + * + * @since 1.5 + */ + @Override + public synchronized void engineSetEntry(String alias, KeyStore.Entry entry, + KeyStore.ProtectionParameter protParam) throws KeyStoreException { + + // get password + if (protParam != null && + !(protParam instanceof KeyStore.PasswordProtection)) { + throw new KeyStoreException("unsupported protection parameter"); + } + KeyStore.PasswordProtection pProtect = null; + if (protParam != null) { + pProtect = (KeyStore.PasswordProtection)protParam; + } + + // set entry + if (entry instanceof KeyStore.TrustedCertificateEntry) { + if (protParam != null && pProtect.getPassword() != null) { + // pre-1.5 style setCertificateEntry did not allow password + throw new KeyStoreException + ("trusted certificate entries are not password-protected"); + } else { + KeyStore.TrustedCertificateEntry tce = + (KeyStore.TrustedCertificateEntry)entry; + setCertEntry(alias, tce.getTrustedCertificate(), + tce.getAttributes()); + + return; + } + } else if (entry instanceof KeyStore.PrivateKeyEntry) { + if (pProtect == null || pProtect.getPassword() == null) { + // pre-1.5 style setKeyEntry required password + throw new KeyStoreException + ("non-null password required to create PrivateKeyEntry"); + } else { + KeyStore.PrivateKeyEntry pke = (KeyStore.PrivateKeyEntry)entry; + setKeyEntry(alias, pke.getPrivateKey(), pProtect, + pke.getCertificateChain(), pke.getAttributes()); + + return; + } + } else if (entry instanceof KeyStore.SecretKeyEntry) { + if (pProtect == null || pProtect.getPassword() == null) { + // pre-1.5 style setKeyEntry required password + throw new KeyStoreException + ("non-null password required to create SecretKeyEntry"); + } else { + KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry; + setKeyEntry(alias, ske.getSecretKey(), pProtect, + (Certificate[])null, ske.getAttributes()); + + return; + } + } + + throw new KeyStoreException + ("unsupported entry type: " + entry.getClass().getName()); + } + + /* + * Assemble the entry attributes + */ + private Set getAttributes(Entry entry) { + + if (entry.attributes == null) { + entry.attributes = new HashSet<>(); + } + + // friendlyName + entry.attributes.add(new PKCS12Attribute( + PKCS9FriendlyName_OID.toString(), entry.alias)); + + // localKeyID + byte[] keyIdValue = entry.keyId; + if (keyIdValue != null) { + entry.attributes.add(new PKCS12Attribute( + PKCS9LocalKeyId_OID.toString(), Debug.toString(keyIdValue))); + } + + // trustedKeyUsage + if (entry instanceof CertEntry) { + ObjectIdentifier[] trustedKeyUsageValue = + ((CertEntry) entry).trustedKeyUsage; + if (trustedKeyUsageValue != null) { + if (trustedKeyUsageValue.length == 1) { // omit brackets + entry.attributes.add(new PKCS12Attribute( + TrustedKeyUsage_OID.toString(), + trustedKeyUsageValue[0].toString())); + } else { // multi-valued + entry.attributes.add(new PKCS12Attribute( + TrustedKeyUsage_OID.toString(), + Arrays.toString(trustedKeyUsageValue))); + } + } + } + + return entry.attributes; + } /* * Generate Hash. @@ -887,11 +1438,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* - * Create PKCS#12 Attributes, friendlyName and localKeyId. + * Create PKCS#12 Attributes, friendlyName, localKeyId and trustedKeyUsage. * * Although attributes are optional, they could be required. * For e.g. localKeyId attribute is required to match the * private key with the associated end-entity certificate. + * The trustedKeyUsage attribute is used to denote a trusted certificate. * * PKCS8ShroudedKeyBags include unique localKeyID and friendlyName. * CertBags may or may not include attributes depending on the type @@ -913,20 +1465,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * friendlyName unique same/ same/ unique * unique unique/ * null + * trustedKeyUsage - - - true * * Note: OpenSSL adds friendlyName for end-entity cert only, and * removes the localKeyID and friendlyName for CA certs. * If the CertBag did not have a friendlyName, most vendors will * add it, and assign it to the DN of the cert. */ - private byte[] getBagAttributes(String alias, byte[] keyId) - throws IOException { + private byte[] getBagAttributes(String alias, byte[] keyId, + Set attributes) throws IOException { + return getBagAttributes(alias, keyId, null, attributes); + } + + private byte[] getBagAttributes(String alias, byte[] keyId, + ObjectIdentifier[] trustedUsage, + Set attributes) throws IOException { byte[] localKeyID = null; byte[] friendlyName = null; + byte[] trustedKeyUsage = null; - // return null if both attributes are null - if ((alias == null) && (keyId == null)) { + // return null if all three attributes are null + if ((alias == null) && (keyId == null) && (trustedKeyUsage == null)) { return null; } @@ -957,6 +1517,20 @@ public final class PKCS12KeyStore extends KeyStoreSpi { localKeyID = bagAttrValue2.toByteArray(); } + // Encode the trustedKeyUsage oid. + if (trustedUsage != null) { + DerOutputStream bagAttr3 = new DerOutputStream(); + bagAttr3.putOID(TrustedKeyUsage_OID); + DerOutputStream bagAttrContent3 = new DerOutputStream(); + DerOutputStream bagAttrValue3 = new DerOutputStream(); + for (ObjectIdentifier usage : trustedUsage) { + bagAttrContent3.putOID(usage); + } + bagAttr3.write(DerValue.tag_Set, bagAttrContent3); + bagAttrValue3.write(DerValue.tag_Sequence, bagAttr3); + trustedKeyUsage = bagAttrValue3.toByteArray(); + } + DerOutputStream attrs = new DerOutputStream(); if (friendlyName != null) { attrs.write(friendlyName); @@ -964,11 +1538,27 @@ public final class PKCS12KeyStore extends KeyStoreSpi { if (localKeyID != null) { attrs.write(localKeyID); } + if (trustedKeyUsage != null) { + attrs.write(trustedKeyUsage); + } + + if (attributes != null) { + for (KeyStore.Entry.Attribute attribute : attributes) { + String attributeName = attribute.getName(); + // skip friendlyName, localKeyId and trustedKeyUsage + if (CORE_ATTRIBUTES[0].equals(attributeName) || + CORE_ATTRIBUTES[1].equals(attributeName) || + CORE_ATTRIBUTES[2].equals(attributeName)) { + continue; + } + attrs.write(((PKCS12Attribute) attribute).getEncoded()); + } + } + bagAttrs.write(DerValue.tag_Set, attrs); return bagAttrs.toByteArray(); } - /* * Create EncryptedData content type, that contains EncryptedContentInfo. * Includes certificates in individual SafeBags of type CertBag. @@ -979,17 +1569,26 @@ public final class PKCS12KeyStore extends KeyStoreSpi { throws CertificateException, IOException { DerOutputStream out = new DerOutputStream(); - for (Enumeration e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration e = engineAliases(); e.hasMoreElements(); ) { String alias = e.nextElement(); - KeyEntry entry = entries.get(alias); + Entry entry = entries.get(alias); // certificate chain - int chainLen; - if (entry.chain == null) { - chainLen = 0; - } else { - chainLen = entry.chain.length; + int chainLen = 1; + Certificate[] certs = null; + + if (entry instanceof PrivateKeyEntry) { + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + if (keyEntry.chain == null) { + chainLen = 0; + } else { + chainLen = keyEntry.chain.length; + } + certs = keyEntry.chain; + + } else if (entry instanceof CertEntry) { + certs = new Certificate[]{((CertEntry) entry).cert}; } for (int i = 0; i < chainLen; i++) { @@ -1003,7 +1602,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // write encoded certs in a context-specific tag DerOutputStream certValue = new DerOutputStream(); - X509Certificate cert = (X509Certificate)entry.chain[i]; + X509Certificate cert = (X509Certificate) certs[i]; certValue.putOctetString(cert.getEncoded()); certBag.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), certValue); @@ -1026,7 +1625,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { byte[] bagAttrs = null; if (i == 0) { // Only End-Entity Cert should have a localKeyId. - bagAttrs = getBagAttributes(entry.alias, entry.keyId); + if (entry instanceof KeyEntry) { + KeyEntry keyEntry = (KeyEntry) entry; + bagAttrs = + getBagAttributes(keyEntry.alias, keyEntry.keyId, + keyEntry.attributes); + } else { + CertEntry certEntry = (CertEntry) entry; + bagAttrs = + getBagAttributes(certEntry.alias, certEntry.keyId, + certEntry.trustedKeyUsage, + certEntry.attributes); + } } else { // Trusted root CA certs and Intermediate CA certs do not // need to have a localKeyId, and hence localKeyId is null @@ -1035,7 +1645,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // certificate chain to have unique or null localKeyID. // However, IE/OpenSSL do not impose this restriction. bagAttrs = getBagAttributes( - cert.getSubjectX500Principal().getName(), null); + cert.getSubjectX500Principal().getName(), null, + entry.attributes); } if (bagAttrs != null) { safeBag.write(bagAttrs); @@ -1065,6 +1676,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * Create SafeContent Data content type. + * Includes encrypted secret key in a SafeBag of type SecretBag. * Includes encrypted private key in a SafeBag of type PKCS8ShroudedKeyBag. * Each PKCS8ShroudedKeyBag includes pkcs12 attributes * (see comments in getBagAttributes) @@ -1073,33 +1685,74 @@ public final class PKCS12KeyStore extends KeyStoreSpi { throws CertificateException, IOException { DerOutputStream out = new DerOutputStream(); - for (Enumeration e = entries.keys(); e.hasMoreElements(); ) { + for (Enumeration e = engineAliases(); e.hasMoreElements(); ) { String alias = e.nextElement(); - KeyEntry entry = entries.get(alias); - - // Create SafeBag of type pkcs8ShroudedKeyBag - DerOutputStream safeBag = new DerOutputStream(); - safeBag.putOID(PKCS8ShroudedKeyBag_OID); - - // get the encrypted private key - byte[] encrBytes = entry.protectedPrivKey; - EncryptedPrivateKeyInfo encrInfo = null; - try { - encrInfo = new EncryptedPrivateKeyInfo(encrBytes); - } catch (IOException ioe) { - throw new IOException("Private key not stored as " - + "PKCS#8 EncryptedPrivateKeyInfo" + ioe.getMessage()); + Entry entry = entries.get(alias); + if (entry == null || (!(entry instanceof KeyEntry))) { + continue; } + DerOutputStream safeBag = new DerOutputStream(); + KeyEntry keyEntry = (KeyEntry) entry; - // Wrap the EncryptedPrivateKeyInfo in a context-specific tag. - DerOutputStream bagValue = new DerOutputStream(); - bagValue.write(encrInfo.getEncoded()); - safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT, + // DER encode the private key + if (keyEntry instanceof PrivateKeyEntry) { + // Create SafeBag of type pkcs8ShroudedKeyBag + safeBag.putOID(PKCS8ShroudedKeyBag_OID); + + // get the encrypted private key + byte[] encrBytes = ((PrivateKeyEntry)keyEntry).protectedPrivKey; + EncryptedPrivateKeyInfo encrInfo = null; + try { + encrInfo = new EncryptedPrivateKeyInfo(encrBytes); + + } catch (IOException ioe) { + throw new IOException("Private key not stored as " + + "PKCS#8 EncryptedPrivateKeyInfo" + + ioe.getMessage()); + } + + // Wrap the EncryptedPrivateKeyInfo in a context-specific tag. + DerOutputStream bagValue = new DerOutputStream(); + bagValue.write(encrInfo.getEncoded()); + safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), bagValue); + // DER encode the secret key + } else if (keyEntry instanceof SecretKeyEntry) { + // Create SafeBag of type SecretBag + safeBag.putOID(SecretBag_OID); + + // Create a SecretBag + DerOutputStream secretBag = new DerOutputStream(); + secretBag.putOID(PKCS8ShroudedKeyBag_OID); + + // Write secret key in a context-specific tag + DerOutputStream secretKeyValue = new DerOutputStream(); + secretKeyValue.putOctetString( + ((SecretKeyEntry) keyEntry).protectedSecretKey); + secretBag.write(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte) 0), secretKeyValue); + + // Wrap SecretBag in a Sequence + DerOutputStream secretBagSeq = new DerOutputStream(); + secretBagSeq.write(DerValue.tag_Sequence, secretBag); + byte[] secretBagValue = secretBagSeq.toByteArray(); + + // Wrap the secret bag in a context-specific tag. + DerOutputStream bagValue = new DerOutputStream(); + bagValue.write(secretBagValue); + + // Write SafeBag value + safeBag.write(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte) 0), bagValue); + } else { + continue; // skip this entry + } + // write SafeBag Attributes - byte[] bagAttrs = getBagAttributes(alias, entry.keyId); + byte[] bagAttrs = + getBagAttributes(alias, entry.keyId, entry.attributes); safeBag.write(bagAttrs); // wrap as Sequence @@ -1143,6 +1796,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); encryptedData = cipher.doFinal(data); + if (debug != null) { + debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() + + ")"); + } + } catch (Exception e) { throw new IOException("Failed to encrypt" + " safe contents entry: " + e, e); @@ -1223,8 +1881,10 @@ public final class PKCS12KeyStore extends KeyStoreSpi { DerValue[] safeContentsArray = as.getSequence(2); int count = safeContentsArray.length; - // reset the count at the start + // reset the counters at the start privateKeyCount = 0; + secretKeyCount = 0; + certificateCount = 0; /* * Spin over the ContentInfos. @@ -1240,11 +1900,21 @@ public final class PKCS12KeyStore extends KeyStoreSpi { contentType = safeContents.getContentType(); safeContentsData = null; if (contentType.equals((Object)ContentInfo.DATA_OID)) { + + if (debug != null) { + debug.println("Loading PKCS#7 data content-type"); + } + safeContentsData = safeContents.getData(); } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) { if (password == null) { continue; } + + if (debug != null) { + debug.println("Loading PKCS#7 encryptedData content-type"); + } + DerInputStream edi = safeContents.getContent().toDerInputStream(); int edVersion = edi.getInteger(); @@ -1281,7 +1951,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { continue; } throw new IOException( - "failed to decrypt safe contents entry: " + e, e); + "failed to decrypt safe contents entry: " + e, e); } } } else { @@ -1312,6 +1982,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi { m.update(authSafeData); byte[] macResult = m.doFinal(); + if (debug != null) { + debug.println("Checking keystore integrity " + + "(MAC algorithm: " + m.getAlgorithm() + ")"); + } + if (!Arrays.equals(macData.getDigest(), macResult)) { throw new SecurityException("Failed PKCS12" + " integrity checking"); @@ -1324,9 +1999,10 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * Match up private keys with certificate chains. */ - KeyEntry[] list = keyList.toArray(new KeyEntry[keyList.size()]); + PrivateKeyEntry[] list = + keyList.toArray(new PrivateKeyEntry[keyList.size()]); for (int m = 0; m < list.length; m++) { - KeyEntry entry = list[m]; + PrivateKeyEntry entry = list[m]; if (entry.keyId != null) { ArrayList chain = new ArrayList(); @@ -1344,6 +2020,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi { entry.chain = chain.toArray(new Certificate[chain.size()]); } } + + if (debug != null) { + if (privateKeyCount > 0) { + debug.println("Loaded " + privateKeyCount + + " protected private key(s)"); + } + if (secretKeyCount > 0) { + debug.println("Loaded " + secretKeyCount + + " protected secret key(s)"); + } + if (certificateCount > 0) { + debug.println("Loaded " + certificateCount + + " certificate(s)"); + } + } + certEntries.clear(); certsMap.clear(); keyList.clear(); @@ -1354,7 +2046,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { * @param entry the KeyEntry to match * @return a certificate, null if not found */ - private X509Certificate findMatchedCertificate(KeyEntry entry) { + private X509Certificate findMatchedCertificate(PrivateKeyEntry entry) { CertEntry keyIdMatch = null; CertEntry aliasMatch = null; for (CertEntry ce: certEntries) { @@ -1398,7 +2090,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } bagValue = bagValue.data.getDerValue(); if (bagId.equals((Object)PKCS8ShroudedKeyBag_OID)) { - KeyEntry kEntry = new KeyEntry(); + PrivateKeyEntry kEntry = new PrivateKeyEntry(); kEntry.protectedPrivKey = bagValue.toByteArray(); bagItem = kEntry; privateKeyCount++; @@ -1416,13 +2108,30 @@ public final class PKCS12KeyStore extends KeyStoreSpi { cert = (X509Certificate)cf.generateCertificate (new ByteArrayInputStream(certValue.getOctetString())); bagItem = cert; + certificateCount++; + } else if (bagId.equals((Object)SecretBag_OID)) { + DerInputStream ss = new DerInputStream(bagValue.toByteArray()); + DerValue[] secretValues = ss.getSequence(2); + ObjectIdentifier secretId = secretValues[0].getOID(); + if (!secretValues[1].isContextSpecific((byte)0)) { + throw new IOException( + "unsupported PKCS12 secret value type " + + secretValues[1].tag); + } + DerValue secretValue = secretValues[1].data.getDerValue(); + SecretKeyEntry kEntry = new SecretKeyEntry(); + kEntry.protectedSecretKey = secretValue.getOctetString(); + bagItem = kEntry; } else { - // log error message for "unsupported PKCS12 bag type" + + if (debug != null) { + debug.println("Unsupported PKCS12 bag type: " + bagId); + } } DerValue[] attrSet; try { - attrSet = sbi.getSet(2); + attrSet = sbi.getSet(3); } catch (IOException e) { // entry does not have attributes // Note: CA certs can have no attributes @@ -1432,11 +2141,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi { String alias = null; byte[] keyId = null; + ObjectIdentifier[] trustedKeyUsage = null; + Set attributes = new HashSet<>(); if (attrSet != null) { for (int j = 0; j < attrSet.length; j++) { - DerInputStream as = - new DerInputStream(attrSet[j].toByteArray()); + byte[] encoded = attrSet[j].toByteArray(); + DerInputStream as = new DerInputStream(encoded); DerValue[] attrSeq = as.getSequence(2); ObjectIdentifier attrId = attrSeq[0].getOID(); DerInputStream vs = @@ -1452,8 +2163,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi { alias = valSet[0].getBMPString(); } else if (attrId.equals((Object)PKCS9LocalKeyId_OID)) { keyId = valSet[0].getOctetString(); + } else if + (attrId.equals((Object)TrustedKeyUsage_OID)) { + trustedKeyUsage = new ObjectIdentifier[valSet.length]; + for (int k = 0; k < valSet.length; k++) { + trustedKeyUsage[k] = valSet[k].getOID(); + } } else { - // log error message for "unknown attr" + attributes.add(new PKCS12Attribute(encoded)); } } } @@ -1469,16 +2186,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi { */ if (bagItem instanceof KeyEntry) { KeyEntry entry = (KeyEntry)bagItem; - if (keyId == null) { - // Insert a localKeyID for the privateKey - // Note: This is a workaround to allow null localKeyID - // attribute in pkcs12 with one private key entry and - // associated cert-chain - if (privateKeyCount == 1) { - keyId = "01".getBytes("UTF8"); - } else { - continue; - } + + if (bagItem instanceof PrivateKeyEntry) { + if (keyId == null) { + // Insert a localKeyID for the privateKey + // Note: This is a workaround to allow null localKeyID + // attribute in pkcs12 with one private key entry and + // associated cert-chain + if (privateKeyCount == 1) { + keyId = "01".getBytes("UTF8"); + } else { + continue; + } + } } entry.keyId = keyId; // restore date if it exists @@ -1496,11 +2216,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi { date = new Date(); } entry.date = date; - keyList.add(entry); - if (alias == null) + + if (bagItem instanceof PrivateKeyEntry) { + keyList.add((PrivateKeyEntry) entry); + } + if (alias == null) { alias = getUnfriendlyName(); + } entry.alias = alias; entries.put(alias.toLowerCase(Locale.ENGLISH), entry); + } else if (bagItem instanceof X509Certificate) { X509Certificate cert = (X509Certificate)bagItem; // Insert a localKeyID for the corresponding cert @@ -1513,7 +2238,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { keyId = "01".getBytes("UTF8"); } } - certEntries.add(new CertEntry(cert, keyId, alias)); + // Trusted certificate + if (trustedKeyUsage != null) { + if (alias == null) { + alias = getUnfriendlyName(); + } + CertEntry certEntry = + new CertEntry(cert, keyId, alias, trustedKeyUsage, + attributes); + entries.put(alias.toLowerCase(Locale.ENGLISH), certEntry); + } else { + certEntries.add(new CertEntry(cert, keyId, alias)); + } X500Principal subjectDN = cert.getSubjectX500Principal(); if (subjectDN != null) { if (!certsMap.containsKey(subjectDN)) { diff --git a/jdk/src/share/classes/sun/security/x509/AlgorithmId.java b/jdk/src/share/classes/sun/security/x509/AlgorithmId.java index e2d6c60c111..f34d973fc73 100644 --- a/jdk/src/share/classes/sun/security/x509/AlgorithmId.java +++ b/jdk/src/share/classes/sun/security/x509/AlgorithmId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -502,6 +502,11 @@ public class AlgorithmId implements Serializable, DerEncoder { return AlgorithmId.ECDH_oid; } + // Secret key algorithms + if (name.equalsIgnoreCase("AES")) { + return AlgorithmId.AES_oid; + } + // Common signature types if (name.equalsIgnoreCase("MD5withRSA") || name.equalsIgnoreCase("MD5/RSA")) { @@ -660,6 +665,12 @@ public class AlgorithmId implements Serializable, DerEncoder { public static final ObjectIdentifier RSA_oid; public static final ObjectIdentifier RSAEncryption_oid; + /* + * COMMON SECRET KEY TYPES + */ + public static final ObjectIdentifier AES_oid = + oid(2, 16, 840, 1, 101, 3, 4, 1); + /* * COMMON SIGNATURE ALGORITHMS */ @@ -893,6 +904,8 @@ public class AlgorithmId implements Serializable, DerEncoder { nameTable.put(EC_oid, "EC"); nameTable.put(ECDH_oid, "ECDH"); + nameTable.put(AES_oid, "AES"); + nameTable.put(sha1WithECDSA_oid, "SHA1withECDSA"); nameTable.put(sha224WithECDSA_oid, "SHA224withECDSA"); nameTable.put(sha256WithECDSA_oid, "SHA256withECDSA"); diff --git a/jdk/src/share/classes/sun/security/x509/URIName.java b/jdk/src/share/classes/sun/security/x509/URIName.java index 9345640ef57..d7dbea95843 100644 --- a/jdk/src/share/classes/sun/security/x509/URIName.java +++ b/jdk/src/share/classes/sun/security/x509/URIName.java @@ -30,7 +30,6 @@ import java.net.URI; import java.net.URISyntaxException; import sun.security.util.*; -import sun.net.www.ParseUtil; /** * This class implements the URIName as required by the GeneralNames @@ -107,13 +106,7 @@ public class URIName implements GeneralNameInterface { try { uri = new URI(name); } catch (URISyntaxException use) { - try { - // Try parsing the URI again after encoding/escaping - // any illegal characters - uri = new URI(ParseUtil.encodePath(name)); - } catch (URISyntaxException use2) { - throw new IOException("invalid URI name:" + name, use2); - } + throw new IOException("invalid URI name:" + name, use); } if (uri.getScheme() == null) { throw new IOException("URI name must include scheme:" + name); diff --git a/jdk/src/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/share/classes/sun/swing/SwingUtilities2.java index 2094ec0c11d..c6134885adf 100644 --- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java +++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java @@ -1879,4 +1879,12 @@ public class SwingUtilities2 { } return -1; } + + public static int getSystemMnemonicKeyMask() { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof SunToolkit) { + return ((SunToolkit) toolkit).getFocusAcceleratorKeyMask(); + } + return InputEvent.ALT_MASK; + } } diff --git a/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java b/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java index a05259e5978..8b033ca3e7f 100644 --- a/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java +++ b/jdk/src/share/classes/sun/swing/WindowsPlacesBar.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 @@ -116,9 +116,6 @@ public class WindowsPlacesBar extends JToolBar icon = fsv.getSystemIcon(files[i]); } buttons[i] = new JToggleButton(folderName, icon); - if (isXPPlatform) { - buttons[i].setText("

    "+folderName+"
    "); - } if (isXPStyle) { buttons[i].putClientProperty("XPStyle.subAppName", "placesbar"); } else { diff --git a/jdk/src/share/classes/sun/text/resources/FormatData.java b/jdk/src/share/classes/sun/text/resources/FormatData.java index d6c306709a8..f31a1d34d09 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources; import java.util.ListResourceBundle; @@ -762,6 +798,14 @@ public class FormatData extends ListResourceBundle { "H:mm", // short time pattern } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "G y MMMM d", + "G y MMM d", + "GGGGG yyyy-MM-dd", + } + }, { "buddhist.DatePatterns", new String[] { "EEEE d MMMM G yyyy", // full date pattern @@ -783,6 +827,14 @@ public class FormatData extends ListResourceBundle { "h:mm a", // short time pattern } }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "G y MMMM d", + "G y MMM d", + "GGGGG yy-MM-dd", + } + }, { "japanese.DatePatterns", new String[] { "GGGG yyyy MMMM d (EEEE)", // full date pattern @@ -796,7 +848,103 @@ public class FormatData extends ListResourceBundle { "{1} {0}" // date-time pattern } }, + { "roc.Eras", + new String[] { + "Before R.O.C.", + "R.O.C.", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "G y MMMM d", + "G y MMM d", + "GGGGG yyy-MM-dd", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, GGGG y MMMM dd", + "GGGG y MMMM d", + "GGGG y MMM d", + "G yyy-MM-dd", + } + }, + { "islamic.MonthNames", + new String[] { + "Muharram", + "Safar", + "Rabi\u02bb I", + "Rabi\u02bb II", + "Jumada I", + "Jumada II", + "Rajab", + "Sha\u02bbban", + "Ramadan", + "Shawwal", + "Dhu\u02bbl-Qi\u02bbdah", + "Dhu\u02bbl-Hijjah", + "", + } + }, + { "islamic.MonthAbbreviations", + new String[] { + "Muh.", + "Saf.", + "Rab. I", + "Rab. II", + "Jum. I", + "Jum. II", + "Raj.", + "Sha.", + "Ram.", + "Shaw.", + "Dhu\u02bbl-Q.", + "Dhu\u02bbl-H.", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "AH", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, MMMM d, y G", + "MMMM d, y G", + "MMM d, y G", + "M/d/yy G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, MMMM d, y GGGG", + "MMMM d, y GGGG", + "MMM d, y GGGG", + "M/d/yy GGGG", + } + }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "Islamic-Civil Calendar" }, + { "calendarname.islamicc", "Islamic-Civil Calendar" }, + { "calendarname.islamic", "Islamic Calendar" }, + { "calendarname.japanese", "Japanese Calendar" }, + { "calendarname.gregorian", "Gregorian Calendar" }, + { "calendarname.gregory", "Gregorian Calendar" }, + { "calendarname.roc", "Minguo Calendar" }, + { "calendarname.buddhist", "Buddhist Calendar" }, + { "field.era", "Era" }, + { "field.year", "Year" }, + { "field.month", "Month" }, + { "field.week", "Week" }, + { "field.weekday", "Day of the Week" }, + { "field.dayperiod", "Dayperiod" }, + { "field.hour", "Hour" }, + { "field.minute", "Minute" }, + { "field.second", "Second" }, + { "field.zone", "Zone" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ar/FormatData_ar.java b/jdk/src/share/classes/sun/text/resources/ar/FormatData_ar.java index a6593b0a45c..127c03a5dab 100644 --- a/jdk/src/share/classes/sun/text/resources/ar/FormatData_ar.java +++ b/jdk/src/share/classes/sun/text/resources/ar/FormatData_ar.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ar; import java.util.ListResourceBundle; @@ -159,6 +195,118 @@ public class FormatData_ar extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE\u060c d MMMM\u060c y G", + "d MMMM\u060c y G", + "dd\u200f/MM\u200f/y G", + "d\u200f/M\u200f/y G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE\u060c d MMMM\u060c y G", + "d MMMM\u060c y G", + "dd\u200f/MM\u200f/y G", + "d\u200f/M\u200f/y G", + } + }, + { "roc.Eras", + new String[] { + "Before R.O.C.", + "\u062c\u0645\u0647\u0648\u0631\u064a\u0629 \u0627\u0644\u0635\u064a", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE\u060c d MMMM\u060c y G", + "d MMMM\u060c y G", + "dd\u200f/MM\u200f/y G", + "d\u200f/M\u200f/y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE\u060c d MMMM\u060c y GGGG", + "d MMMM\u060c y GGGG", + "dd\u200f/MM\u200f/y GGGG", + "d\u200f/M\u200f/y GGGG", + } + }, + { "islamic.MonthNames", + new String[] { + "\u0645\u062d\u0631\u0645", + "\u0635\u0641\u0631", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0623\u0648\u0644", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0622\u062e\u0631", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0623\u0648\u0644\u0649", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0622\u062e\u0631\u0629", + "\u0631\u062c\u0628", + "\u0634\u0639\u0628\u0627\u0646", + "\u0631\u0645\u0636\u0627\u0646", + "\u0634\u0648\u0627\u0644", + "\u0630\u0648 \u0627\u0644\u0642\u0639\u062f\u0629", + "\u0630\u0648 \u0627\u0644\u062d\u062c\u0629", + "", + } + }, + { "islamic.MonthAbbreviations", + new String[] { + "\u0645\u062d\u0631\u0645", + "\u0635\u0641\u0631", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0623\u0648\u0644", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0622\u062e\u0631", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0623\u0648\u0644\u0649", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0622\u062e\u0631\u0629", + "\u0631\u062c\u0628", + "\u0634\u0639\u0628\u0627\u0646", + "\u0631\u0645\u0636\u0627\u0646", + "\u0634\u0648\u0627\u0644", + "\u0630\u0648 \u0627\u0644\u0642\u0639\u062f\u0629", + "\u0630\u0648 \u0627\u0644\u062d\u062c\u0629", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "\u0647\u0640", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE\u060c d MMMM y", + "d MMMM y", + "d MMM\u060c y G", + "d\u200f/M\u200f/yyyy", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE\u060c d MMMM y", + "d MMMM y", + "d MMM\u060c y GGGG", + "d\u200f/M\u200f/yyyy", + } + }, + { "calendarname.islamic-civil", "\u062a\u0642\u0648\u064a\u0645 \u0627\u0633\u0644\u0627\u0645\u064a \u0645\u062f\u0646\u064a" }, + { "calendarname.islamicc", "\u062a\u0642\u0648\u064a\u0645 \u0627\u0633\u0644\u0627\u0645\u064a \u0645\u062f\u0646\u064a" }, + { "calendarname.islamic", "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0647\u062c\u0631\u064a" }, + { "calendarname.japanese", "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u064a\u0627\u0628\u0627\u0646\u064a" }, + { "calendarname.gregorian", "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0645\u064a\u0644\u0627\u062f\u064a" }, + { "calendarname.gregory", "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0645\u064a\u0644\u0627\u062f\u064a" }, + { "calendarname.roc", "\u062a\u0642\u0648\u064a\u0645 \u0645\u064a\u0646\u062c\u0648" }, + { "calendarname.buddhist", "\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0628\u0648\u0630\u064a" }, + { "field.era", "\u0627\u0644\u0639\u0635\u0631" }, + { "field.year", "\u0627\u0644\u0633\u0646\u0629" }, + { "field.month", "\u0627\u0644\u0634\u0647\u0631" }, + { "field.week", "\u0627\u0644\u0623\u0633\u0628\u0648\u0639" }, + { "field.weekday", "\u0627\u0644\u064a\u0648\u0645" }, + { "field.dayperiod", "\u0635/\u0645" }, + { "field.hour", "\u0627\u0644\u0633\u0627\u0639\u0627\u062a" }, + { "field.minute", "\u0627\u0644\u062f\u0642\u0627\u0626\u0642" }, + { "field.second", "\u0627\u0644\u062b\u0648\u0627\u0646\u064a" }, + { "field.zone", "\u0627\u0644\u062a\u0648\u0642\u064a\u062a" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/be/FormatData_be.java b/jdk/src/share/classes/sun/text/resources/be/FormatData_be.java index 7bf6c012163..84c15394658 100644 --- a/jdk/src/share/classes/sun/text/resources/be/FormatData_be.java +++ b/jdk/src/share/classes/sun/text/resources/be/FormatData_be.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.be; import java.util.ListResourceBundle; @@ -178,6 +214,29 @@ public class FormatData_be extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d MMMM y G", + "d MMMM y G", + "d MMM y G", + "d.M.yy", + } + }, + { "calendarname.islamic-civil", "\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u0441\u0432\u0435\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.islamicc", "\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u0441\u0432\u0435\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.islamic", "\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.buddhist", "\u0431\u0443\u0434\u044b\u0441\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.japanese", "\u044f\u043f\u043e\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.gregorian", "\u0433\u0440\u044d\u0433\u0430\u0440\u044b\u044f\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "calendarname.gregory", "\u0433\u0440\u044d\u0433\u0430\u0440\u044b\u044f\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440" }, + { "field.era", "\u044d\u0440\u0430" }, + { "field.year", "\u0433\u043e\u0434" }, + { "field.month", "\u043c\u0435\u0441\u044f\u0446" }, + { "field.week", "\u0442\u044b\u0434\u0437\u0435\u043d\u044c" }, + { "field.weekday", "\u0434\u0437\u0435\u043d\u044c \u0442\u044b\u0434\u043d\u044f" }, + { "field.hour", "\u0433\u0430\u0434\u0437\u0456\u043d\u0430" }, + { "field.minute", "\u0445\u0432\u0456\u043b\u0456\u043d\u0430" }, + { "field.second", "\u0441\u0435\u043a\u0443\u043d\u0434\u0430" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/bg/FormatData_bg.java b/jdk/src/share/classes/sun/text/resources/bg/FormatData_bg.java index 2b7285eefad..2d9ec8da0de 100644 --- a/jdk/src/share/classes/sun/text/resources/bg/FormatData_bg.java +++ b/jdk/src/share/classes/sun/text/resources/bg/FormatData_bg.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.bg; import java.util.ListResourceBundle; @@ -161,6 +197,41 @@ public class FormatData_bg extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "islamic.MonthNames", + new String[] { + "\u043c\u0443\u0445\u0430\u0440\u0430\u043c", + "\u0441\u0430\u0444\u0430\u0440", + "\u0440\u0430\u0431\u0438-1", + "\u0440\u0430\u0431\u0438-2", + "\u0434\u0436\u0443\u043c\u0430\u0434\u0430-1", + "\u0434\u0436\u0443\u043c\u0430\u0434\u0430-2", + "\u0440\u0430\u0434\u0436\u0430\u0431", + "\u0448\u0430\u0431\u0430\u043d", + "\u0440\u0430\u043c\u0430\u0437\u0430\u043d", + "\u0428\u0430\u0432\u0430\u043b", + "\u0414\u0445\u0443\u043b-\u041a\u0430\u0430\u0434\u0430", + "\u0414\u0445\u0443\u043b-\u0445\u0438\u0434\u0436\u0430", + "", + } + }, + { "calendarname.islamic-civil", "\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u0435\u043d \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamicc", "\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u0435\u043d \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamic", "\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.japanese", "\u042f\u043f\u043e\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregorian", "\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregory", "\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.roc", "\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u043d\u0430 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0430 \u041a\u0438\u0442\u0430\u0439" }, + { "calendarname.buddhist", "\u0411\u0443\u0434\u0438\u0441\u0442\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "field.era", "\u0435\u0440\u0430" }, + { "field.year", "\u0433\u043e\u0434\u0438\u043d\u0430" }, + { "field.month", "\u043c\u0435\u0441\u0435\u0446" }, + { "field.week", "\u0441\u0435\u0434\u043c\u0438\u0446\u0430" }, + { "field.weekday", "\u0414\u0435\u043d \u043e\u0442 \u0441\u0435\u0434\u043c\u0438\u0446\u0430\u0442\u0430" }, + { "field.dayperiod", "\u0434\u0435\u043d" }, + { "field.hour", "\u0447\u0430\u0441" }, + { "field.minute", "\u043c\u0438\u043d\u0443\u0442\u0430" }, + { "field.second", "\u0441\u0435\u043a\u0443\u043d\u0434\u0430" }, + { "field.zone", "\u0437\u043e\u043d\u0430" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ca/FormatData_ca.java b/jdk/src/share/classes/sun/text/resources/ca/FormatData_ca.java index d6774dbacb6..10522d5e22c 100644 --- a/jdk/src/share/classes/sun/text/resources/ca/FormatData_ca.java +++ b/jdk/src/share/classes/sun/text/resources/ca/FormatData_ca.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ca; import java.util.ListResourceBundle; @@ -217,6 +253,24 @@ public class FormatData_ca extends ListResourceBundle { } }, { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "calendari civil isl\u00e0mic" }, + { "calendarname.islamicc", "calendari civil isl\u00e0mic" }, + { "calendarname.roc", "calendari de la Rep\u00fablica de Xina" }, + { "calendarname.islamic", "calendari musulm\u00e0" }, + { "calendarname.buddhist", "calendari budista" }, + { "calendarname.japanese", "calendari japon\u00e8s" }, + { "calendarname.gregorian", "calendari gregori\u00e0" }, + { "calendarname.gregory", "calendari gregori\u00e0" }, + { "field.era", "era" }, + { "field.year", "any" }, + { "field.month", "mes" }, + { "field.week", "setmana" }, + { "field.weekday", "dia de la setmana" }, + { "field.dayperiod", "a.m./p.m." }, + { "field.hour", "hora" }, + { "field.minute", "minut" }, + { "field.second", "segon" }, + { "field.zone", "zona" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/cs/FormatData_cs.java b/jdk/src/share/classes/sun/text/resources/cs/FormatData_cs.java index e0d34098b09..cb2d780cb82 100644 --- a/jdk/src/share/classes/sun/text/resources/cs/FormatData_cs.java +++ b/jdk/src/share/classes/sun/text/resources/cs/FormatData_cs.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.cs; import java.util.ListResourceBundle; @@ -201,6 +237,22 @@ public class FormatData_cs extends ListResourceBundle { } }, { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "Muslimsk\u00fd ob\u010dansk\u00fd kalend\u00e1\u0159" }, + { "calendarname.islamicc", "Muslimsk\u00fd ob\u010dansk\u00fd kalend\u00e1\u0159" }, + { "calendarname.islamic", "Muslimsk\u00fd kalend\u00e1\u0159" }, + { "calendarname.buddhist", "Buddhistick\u00fd kalend\u00e1\u0159" }, + { "calendarname.japanese", "Japonsk\u00fd kalend\u00e1\u0159" }, + { "calendarname.gregorian", "Gregori\u00e1nsk\u00fd kalend\u00e1\u0159" }, + { "calendarname.gregory", "Gregori\u00e1nsk\u00fd kalend\u00e1\u0159" }, + { "field.year", "Rok" }, + { "field.month", "M\u011bs\u00edc" }, + { "field.week", "T\u00fdden" }, + { "field.weekday", "Den v t\u00fddnu" }, + { "field.dayperiod", "AM/PM" }, + { "field.hour", "Hodina" }, + { "field.minute", "Minuta" }, + { "field.second", "Sekunda" }, + { "field.zone", "\u010casov\u00e9 p\u00e1smo" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/da/FormatData_da.java b/jdk/src/share/classes/sun/text/resources/da/FormatData_da.java index 2686877c0a3..295a5aaddf6 100644 --- a/jdk/src/share/classes/sun/text/resources/da/FormatData_da.java +++ b/jdk/src/share/classes/sun/text/resources/da/FormatData_da.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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.da; import java.util.ListResourceBundle; @@ -172,6 +208,64 @@ public class FormatData_da extends ListResourceBundle { } }, { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d/M/y GGGGG", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d/M/y GGGGG", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d. MMM y GGGG", + "d/M/y G", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d/M/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d. MMM y GGGG", + "d/M/y GGGG", + } + }, + { "calendarname.islamic-civil", "verdslig islamisk kalender" }, + { "calendarname.islamicc", "verdslig islamisk kalender" }, + { "calendarname.roc", "kalender for Republikken Kina" }, + { "calendarname.islamic", "islamisk kalender" }, + { "calendarname.buddhist", "buddhistisk kalender" }, + { "calendarname.japanese", "japansk kalender" }, + { "calendarname.gregorian", "gregoriansk kalender" }, + { "calendarname.gregory", "gregoriansk kalender" }, + { "field.era", "\u00e6ra" }, + { "field.year", "\u00e5r" }, + { "field.month", "m\u00e5ned" }, + { "field.week", "uge" }, + { "field.weekday", "ugedag" }, + { "field.dayperiod", "dagtid" }, + { "field.hour", "time" }, + { "field.minute", "minut" }, + { "field.second", "sekund" }, + { "field.zone", "tidszone" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/de/FormatData_de.java b/jdk/src/share/classes/sun/text/resources/de/FormatData_de.java index 3f55bb20ba6..e8a6c924831 100644 --- a/jdk/src/share/classes/sun/text/resources/de/FormatData_de.java +++ b/jdk/src/share/classes/sun/text/resources/de/FormatData_de.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.de; import java.util.ListResourceBundle; @@ -178,6 +214,72 @@ public class FormatData_de extends ListResourceBundle { } }, { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d.M.yyyy", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d.M.y GGGGG", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d.M.y GGGGG", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d. MMM y GGGG", + "d.M.y G", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d.M.y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d. MMM y GGGG", + "d.M.y GGGG", + } + }, + { "calendarname.islamic-civil", "B\u00fcrgerlicher islamischer Kalender" }, + { "calendarname.islamicc", "B\u00fcrgerlicher islamischer Kalender" }, + { "calendarname.roc", "Kalender der Republik China" }, + { "calendarname.islamic", "Islamischer Kalender" }, + { "calendarname.buddhist", "Buddhistischer Kalender" }, + { "calendarname.japanese", "Japanischer Kalender" }, + { "calendarname.gregorian", "Gregorianischer Kalender" }, + { "calendarname.gregory", "Gregorianischer Kalender" }, + { "field.era", "Epoche" }, + { "field.year", "Jahr" }, + { "field.month", "Monat" }, + { "field.week", "Woche" }, + { "field.weekday", "Wochentag" }, + { "field.dayperiod", "Tagesh\u00e4lfte" }, + { "field.hour", "Stunde" }, + { "field.minute", "Minute" }, + { "field.second", "Sekunde" }, + { "field.zone", "Zone" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/el/FormatData_el.java b/jdk/src/share/classes/sun/text/resources/el/FormatData_el.java index fd91ad2aea3..608ae6d25f2 100644 --- a/jdk/src/share/classes/sun/text/resources/el/FormatData_el.java +++ b/jdk/src/share/classes/sun/text/resources/el/FormatData_el.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -41,6 +41,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.el; import java.util.ListResourceBundle; @@ -178,6 +214,62 @@ public class FormatData_el extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM, y G", + "d/M/yyyy", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM, y G", + "d/M/yy", + } + }, + { "roc.Eras", + new String[] { + "\u03a0\u03c1\u03b9\u03bd R.O.C.", + "R.O.C.", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM, y G", + "d/M/y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d MMMM, y GGGG", + "d MMMM, y GGGG", + "d MMM, y GGGG", + "d/M/y GGGG", + } + }, + { "calendarname.islamic-civil", "\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b1\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.islamicc", "\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b1\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.islamic", "\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.japanese", "\u0399\u03b1\u03c0\u03c9\u03bd\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.gregorian", "\u0393\u03c1\u03b7\u03b3\u03bf\u03c1\u03b9\u03b1\u03bd\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.gregory", "\u0393\u03c1\u03b7\u03b3\u03bf\u03c1\u03b9\u03b1\u03bd\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "calendarname.roc", "\u0397\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03c4\u03b7\u03c2 \u0394\u03b7\u03bc\u03bf\u03ba\u03c1\u03b1\u03c4\u03af\u03b1\u03c2 \u03c4\u03b7\u03c2 \u039a\u03af\u03bd\u03b1\u03c2" }, + { "calendarname.buddhist", "\u0392\u03bf\u03c5\u03b4\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf" }, + { "field.era", "\u03a0\u03b5\u03c1\u03af\u03bf\u03b4\u03bf\u03c2" }, + { "field.year", "\u0388\u03c4\u03bf\u03c2" }, + { "field.month", "\u039c\u03ae\u03bd\u03b1\u03c2" }, + { "field.week", "\u0395\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b1" }, + { "field.weekday", "\u0397\u03bc\u03ad\u03c1\u03b1 \u03b5\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b1\u03c2" }, + { "field.dayperiod", "\u03c0.\u03bc./\u03bc.\u03bc." }, + { "field.hour", "\u038f\u03c1\u03b1" }, + { "field.minute", "\u039b\u03b5\u03c0\u03c4\u03cc" }, + { "field.second", "\u0394\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03bf" }, + { "field.zone", "\u0396\u03ce\u03bd\u03b7" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/es/FormatData_es.java b/jdk/src/share/classes/sun/text/resources/es/FormatData_es.java index f19685dd83d..7ea5b998221 100644 --- a/jdk/src/share/classes/sun/text/resources/es/FormatData_es.java +++ b/jdk/src/share/classes/sun/text/resources/es/FormatData_es.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.es; import java.util.ListResourceBundle; @@ -159,6 +195,72 @@ public class FormatData_es extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/y G", + "dd/MM/y G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/y G", + "dd/MM/y GGGGG", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/y G", + "dd/MM/y GGGGG", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y GGGG", + "d 'de' MMMM 'de' y GGGG", + "dd/MM/y GGGG", + "dd/MM/y G", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/y G", + "dd/MM/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y GGGG", + "d 'de' MMMM 'de' y GGGG", + "dd/MM/y GGGG", + "dd/MM/y GGGG", + } + }, + { "calendarname.islamic-civil", "calendario civil isl\u00e1mico" }, + { "calendarname.islamicc", "calendario civil isl\u00e1mico" }, + { "calendarname.islamic", "calendario isl\u00e1mico" }, + { "calendarname.japanese", "calendario japon\u00e9s" }, + { "calendarname.gregorian", "calendario gregoriano" }, + { "calendarname.gregory", "calendario gregoriano" }, + { "calendarname.roc", "calendario de la Rep\u00fablica de China" }, + { "calendarname.buddhist", "calendario budista" }, + { "field.era", "era" }, + { "field.year", "a\u00f1o" }, + { "field.month", "mes" }, + { "field.week", "semana" }, + { "field.weekday", "d\u00eda de la semana" }, + { "field.dayperiod", "periodo del d\u00eda" }, + { "field.hour", "hora" }, + { "field.minute", "minuto" }, + { "field.second", "segundo" }, + { "field.zone", "zona" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/et/FormatData_et.java b/jdk/src/share/classes/sun/text/resources/et/FormatData_et.java index 844b8af4285..a68a22fc464 100644 --- a/jdk/src/share/classes/sun/text/resources/et/FormatData_et.java +++ b/jdk/src/share/classes/sun/text/resources/et/FormatData_et.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.et; import java.util.ListResourceBundle; @@ -158,6 +194,24 @@ public class FormatData_et extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "calendarname.islamic-civil", "islami ilmalik kalender" }, + { "calendarname.islamicc", "islami ilmalik kalender" }, + { "calendarname.roc", "Hiina Vabariigi kalender" }, + { "calendarname.islamic", "islamikalender" }, + { "calendarname.buddhist", "budistlik kalender" }, + { "calendarname.japanese", "Jaapani kalender" }, + { "calendarname.gregorian", "Gregoriuse kalender" }, + { "calendarname.gregory", "Gregoriuse kalender" }, + { "field.era", "ajastu" }, + { "field.year", "aasta" }, + { "field.month", "kuu" }, + { "field.week", "n\u00e4dal" }, + { "field.weekday", "n\u00e4dalap\u00e4ev" }, + { "field.dayperiod", "enne/p\u00e4rast l\u00f5unat" }, + { "field.hour", "tund" }, + { "field.minute", "minut" }, + { "field.second", "sekund" }, + { "field.zone", "v\u00f6\u00f6nd" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/fi/FormatData_fi.java b/jdk/src/share/classes/sun/text/resources/fi/FormatData_fi.java index 91c5ea9a57a..a7b77a7e425 100644 --- a/jdk/src/share/classes/sun/text/resources/fi/FormatData_fi.java +++ b/jdk/src/share/classes/sun/text/resources/fi/FormatData_fi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.fi; import java.util.ListResourceBundle; @@ -200,6 +236,14 @@ public class FormatData_fi extends ListResourceBundle { "H:mm", // short time pattern } }, + { "cldr.DatePatterns", + new String[] { + "cccc, d. MMMM y", + "d. MMMM y", + "d.M.yyyy", + "d.M.yyyy", + } + }, { "DatePatterns", new String[] { "d. MMMM'ta 'yyyy", // full date pattern @@ -226,6 +270,89 @@ public class FormatData_fi extends ListResourceBundle { "ip.", } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "cccc d. MMMM y G", + "d. MMMM y G", + "d.M.y G", + "d.M.y G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "cccc d. MMMM y G", + "d. MMMM y G", + "d.M.y G", + "d.M.y G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "cccc d. MMMM y G", + "d. MMMM y G", + "d.M.y G", + "d.M.y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d.M.y GGGG", + "d.M.y GGGG", + } + }, + { "islamic.MonthNames", + new String[] { + "muharram", + "safar", + "rabi\u2019 al-awwal", + "rabi\u2019 al-akhir", + "d\u017eumada-l-ula", + "d\u017eumada-l-akhira", + "rad\u017eab", + "\u0161a\u2019ban", + "ramadan", + "\u0161awwal", + "dhu-l-qa\u2019da", + "dhu-l-hidd\u017ea", + "", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "cccc d. MMMM y G", + "d. MMMM y G", + "d.M.y G", + "d.M.y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d. MMMM y GGGG", + "d. MMMM y GGGG", + "d.M.y GGGG", + "d.M.y GGGG", + } + }, + { "calendarname.islamic-civil", "islamilainen siviilikalenteri" }, + { "calendarname.islamicc", "islamilainen siviilikalenteri" }, + { "calendarname.islamic", "islamilainen kalenteri" }, + { "calendarname.japanese", "japanilainen kalenteri" }, + { "calendarname.gregorian", "gregoriaaninen kalenteri" }, + { "calendarname.gregory", "gregoriaaninen kalenteri" }, + { "calendarname.roc", "Kiinan tasavallan kalenteri" }, + { "calendarname.buddhist", "buddhalainen kalenteri" }, + { "field.era", "aikakausi" }, + { "field.year", "vuosi" }, + { "field.month", "kuukausi" }, + { "field.week", "viikko" }, + { "field.weekday", "viikonp\u00e4iv\u00e4" }, + { "field.dayperiod", "vuorokaudenaika" }, + { "field.hour", "tunti" }, + { "field.minute", "minuutti" }, + { "field.second", "sekunti" }, + { "field.zone", "aikavy\u00f6hyke" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/fr/FormatData_fr.java b/jdk/src/share/classes/sun/text/resources/fr/FormatData_fr.java index f0354ec1066..ec3493700b7 100644 --- a/jdk/src/share/classes/sun/text/resources/fr/FormatData_fr.java +++ b/jdk/src/share/classes/sun/text/resources/fr/FormatData_fr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.fr; import java.util.ListResourceBundle; @@ -165,6 +201,112 @@ public class FormatData_fr extends ListResourceBundle { } }, { "DateTimePatternChars", "GaMjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM, y G", + "d/M/yyyy", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM, y G", + "d/M/y GGGGG", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM, y G", + "d/M/y GGGGG", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM, y GGGG", + "d/M/y G", + } + }, + { "islamic.MonthNames", + new String[] { + "Mouharram", + "Safar", + "Rabi\u02bb-oul-Aououal", + "Rabi\u02bb-out-Tani", + "Djoumada-l-Oula", + "Djoumada-t-Tania", + "Radjab", + "Cha\u02bbban", + "Ramadan", + "Chaououal", + "Dou-l-Qa\u02bbda", + "Dou-l-Hidjja", + "", + } + }, + { "islamic.MonthAbbreviations", + new String[] { + "Mouh.", + "Saf.", + "Rabi\u02bb-oul-A.", + "Rabi\u02bb-out-T.", + "Djoum.-l-O.", + "Djoum.-t-T.", + "Radj.", + "Cha.", + "Ram.", + "Chaou.", + "Dou-l-Q.", + "Dou-l-H.", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "AH", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM, y G", + "d/M/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM, y GGGG", + "d/M/y GGGG", + } + }, + { "calendarname.islamic-civil", "Calendrier civil musulman" }, + { "calendarname.islamicc", "Calendrier civil musulman" }, + { "calendarname.islamic", "Calendrier musulman" }, + { "calendarname.japanese", "Calendrier japonais" }, + { "calendarname.gregorian", "Calendrier gr\u00e9gorien" }, + { "calendarname.gregory", "Calendrier gr\u00e9gorien" }, + { "calendarname.roc", "Calendrier r\u00e9publicain chinois" }, + { "calendarname.buddhist", "Calendrier bouddhiste" }, + { "field.era", "\u00e8re" }, + { "field.year", "ann\u00e9e" }, + { "field.month", "mois" }, + { "field.week", "semaine" }, + { "field.weekday", "jour de la semaine" }, + { "field.dayperiod", "cadran" }, + { "field.hour", "heure" }, + { "field.minute", "minute" }, + { "field.second", "seconde" }, + { "field.zone", "fuseau horaire" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/hi/FormatData_hi_IN.java b/jdk/src/share/classes/sun/text/resources/hi/FormatData_hi_IN.java index 7f1deb81c3a..61711a0e322 100644 --- a/jdk/src/share/classes/sun/text/resources/hi/FormatData_hi_IN.java +++ b/jdk/src/share/classes/sun/text/resources/hi/FormatData_hi_IN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.hi; import java.util.ListResourceBundle; @@ -159,6 +195,24 @@ public class FormatData_hi_IN extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u0928\u093e\u0917\u0930\u093f\u0915 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.islamicc", "\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u0928\u093e\u0917\u0930\u093f\u0915 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.roc", "\u091a\u0940\u0928\u0940 \u0917\u0923\u0924\u0902\u0924\u094d\u0930 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.islamic", "\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.buddhist", "\u092c\u094c\u0926\u094d\u0927 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.japanese", "\u091c\u093e\u092a\u093e\u0928\u0940 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.gregorian", "\u0917\u094d\u0930\u0947\u0917\u0930\u0940 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "calendarname.gregory", "\u0917\u094d\u0930\u0947\u0917\u0930\u0940 \u092a\u0902\u091a\u093e\u0902\u0917" }, + { "field.era", "\u092f\u0941\u0917" }, + { "field.year", "\u0935\u0930\u094d\u0937" }, + { "field.month", "\u092e\u093e\u0938" }, + { "field.week", "\u0938\u092a\u094d\u0924\u093e\u0939" }, + { "field.weekday", "\u0938\u092a\u094d\u0924\u093e\u0939 \u0915\u093e \u0926\u093f\u0928" }, + { "field.dayperiod", "\u0938\u092e\u092f \u0905\u0935\u0927\u093f" }, + { "field.hour", "\u0918\u0902\u091f\u093e" }, + { "field.minute", "\u092e\u093f\u0928\u091f" }, + { "field.second", "\u0938\u0947\u0915\u0947\u0902\u0921" }, + { "field.zone", "\u0915\u094d\u0937\u0947\u0924\u094d\u0930" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/hr/FormatData_hr.java b/jdk/src/share/classes/sun/text/resources/hr/FormatData_hr.java index cec08671ca1..ff37b50bfa6 100644 --- a/jdk/src/share/classes/sun/text/resources/hr/FormatData_hr.java +++ b/jdk/src/share/classes/sun/text/resources/hr/FormatData_hr.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.hr; import java.util.ListResourceBundle; @@ -214,6 +250,62 @@ public class FormatData_hr extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d. MMMM y. G", + "d. MMMM y. G", + "d. M. y. G", + "d.M.y.", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d. MMMM y. G", + "d. MMMM y. G", + "d. M. y. G", + "d.M.y. G", + } + }, + { "roc.Eras", + new String[] { + "prije R.O.C.", + "R.O.C.", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d. MMMM y. G", + "d. MMMM y. G", + "d. M. y. G", + "d.M.y. G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d. MMMM y. GGGG", + "d. MMMM y. GGGG", + "d. M. y. GGGG", + "d.M.y. GGGG", + } + }, + { "calendarname.islamic-civil", "islamski civilni kalendar" }, + { "calendarname.islamicc", "islamski civilni kalendar" }, + { "calendarname.roc", "kalendar Republike Kine" }, + { "calendarname.islamic", "islamski kalendar" }, + { "calendarname.buddhist", "budisti\u010dki kalendar" }, + { "calendarname.japanese", "japanski kalendar" }, + { "calendarname.gregorian", "gregorijanski kalendar" }, + { "calendarname.gregory", "gregorijanski kalendar" }, + { "field.era", "era" }, + { "field.year", "godina" }, + { "field.month", "mjesec" }, + { "field.week", "tjedan" }, + { "field.weekday", "dan u tjednu" }, + { "field.dayperiod", "dio dana" }, + { "field.hour", "sat" }, + { "field.minute", "minuta" }, + { "field.second", "sekunda" }, + { "field.zone", "zona" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/hu/FormatData_hu.java b/jdk/src/share/classes/sun/text/resources/hu/FormatData_hu.java index 0f00a40aa5f..8d2f4d8adb4 100644 --- a/jdk/src/share/classes/sun/text/resources/hu/FormatData_hu.java +++ b/jdk/src/share/classes/sun/text/resources/hu/FormatData_hu.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.hu; import java.util.ListResourceBundle; @@ -164,6 +200,47 @@ public class FormatData_hu extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "islamic.MonthNames", + new String[] { + "Moharrem", + "Safar", + "R\u00e9bi el avvel", + "R\u00e9bi el accher", + "Dsem\u00e1di el avvel", + "Dsem\u00e1di el accher", + "Redseb", + "Sab\u00e1n", + "Ramad\u00e1n", + "Sevv\u00e1l", + "Ds\u00fcl kade", + "Ds\u00fcl hedse", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "MF", + } + }, + { "calendarname.islamic-civil", "iszl\u00e1m civil napt\u00e1r" }, + { "calendarname.islamicc", "iszl\u00e1m civil napt\u00e1r" }, + { "calendarname.islamic", "iszl\u00e1m napt\u00e1r" }, + { "calendarname.japanese", "jap\u00e1n napt\u00e1r" }, + { "calendarname.gregorian", "Gergely-napt\u00e1r" }, + { "calendarname.gregory", "Gergely-napt\u00e1r" }, + { "calendarname.roc", "K\u00ednai k\u00f6zt\u00e1rsas\u00e1gi napt\u00e1r" }, + { "calendarname.buddhist", "buddhista napt\u00e1r" }, + { "field.era", "\u00e9ra" }, + { "field.year", "\u00e9v" }, + { "field.month", "h\u00f3nap" }, + { "field.week", "h\u00e9t" }, + { "field.weekday", "h\u00e9t napja" }, + { "field.dayperiod", "napszak" }, + { "field.hour", "\u00f3ra" }, + { "field.minute", "perc" }, + { "field.second", "m\u00e1sodperc" }, + { "field.zone", "z\u00f3na" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/is/FormatData_is.java b/jdk/src/share/classes/sun/text/resources/is/FormatData_is.java index 6b6d92c6421..b9324a7bf5a 100644 --- a/jdk/src/share/classes/sun/text/resources/is/FormatData_is.java +++ b/jdk/src/share/classes/sun/text/resources/is/FormatData_is.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.is; import java.util.ListResourceBundle; @@ -180,6 +216,13 @@ public class FormatData_is extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "\u00cdslamskt borgaradagatal" }, + { "calendarname.islamicc", "\u00cdslamskt borgaradagatal" }, + { "calendarname.islamic", "\u00cdslamskt dagatal" }, + { "calendarname.buddhist", "B\u00fadd\u00edskt dagatal" }, + { "calendarname.japanese", "Japanskt dagatal" }, + { "calendarname.gregorian", "Gregor\u00edskt dagatal" }, + { "calendarname.gregory", "Gregor\u00edskt dagatal" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/it/FormatData_it.java b/jdk/src/share/classes/sun/text/resources/it/FormatData_it.java index 5b3fa9ca82e..e3ca1d05fb3 100644 --- a/jdk/src/share/classes/sun/text/resources/it/FormatData_it.java +++ b/jdk/src/share/classes/sun/text/resources/it/FormatData_it.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.it; import java.util.ListResourceBundle; @@ -175,6 +211,71 @@ public class FormatData_it extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "dd MMMM y G", + "dd/MMM/y G", + "dd/MM/y G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "dd MMMM y G", + "dd/MMM/y G", + "dd/MM/y G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "dd MMMM y G", + "dd/MMM/y G", + "dd/MM/y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "dd MMMM y GGGG", + "dd/MMM/y GGGG", + "dd/MM/y GGGG", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "dd MMMM y G", + "dd/MMM/y G", + "dd/MM/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "dd MMMM y GGGG", + "dd/MMM/y GGGG", + "dd/MM/y GGGG", + } + }, + { "calendarname.islamic-civil", "calendario civile islamico" }, + { "calendarname.islamicc", "calendario civile islamico" }, + { "calendarname.islamic", "calendario islamico" }, + { "calendarname.buddhist", "calendario buddista" }, + { "calendarname.japanese", "calendario giapponese" }, + { "calendarname.gregorian", "calendario gregoriano" }, + { "calendarname.gregory", "calendario gregoriano" }, + { "field.era", "era" }, + { "field.year", "anno" }, + { "field.month", "mese" }, + { "field.week", "settimana" }, + { "field.weekday", "giorno della settimana" }, + { "field.dayperiod", "periodo del giorno" }, + { "field.hour", "ora" }, + { "field.minute", "minuto" }, + { "field.second", "secondo" }, + { "field.zone", "zona" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/iw/FormatData_iw.java b/jdk/src/share/classes/sun/text/resources/iw/FormatData_iw.java index 80fb1ac4b83..61d82fbcaaf 100644 --- a/jdk/src/share/classes/sun/text/resources/iw/FormatData_iw.java +++ b/jdk/src/share/classes/sun/text/resources/iw/FormatData_iw.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.iw; import java.util.ListResourceBundle; @@ -171,6 +207,46 @@ public class FormatData_iw extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "islamic.MonthNames", + new String[] { + "\u05de\u05d5\u05d7\u05e8\u05dd", + "\u05e1\u05e4\u05e8", + "\u05e8\u05d1\u05d9\u05e2 \u05d0\u05dc-\u05d0\u05d5\u05d5\u05d0\u05dc", + "\u05e8\u05d1\u05d9\u05e2 \u05d0\u05dc-\u05ea\u05e0\u05d9", + "\u05d2\u05f3\u05d5\u05de\u05d3\u05d4 \u05d0\u05dc-\u05d0\u05d5\u05d5\u05d0\u05dc", + "\u05d2\u05f3\u05d5\u05de\u05d3\u05d4 \u05d0\u05dc-\u05ea\u05e0\u05d9", + "\u05e8\u05d2\u05f3\u05d0\u05d1", + "\u05e9\u05e2\u05d1\u05d0\u05df", + "\u05e8\u05d0\u05de\u05d3\u05df", + "\u05e9\u05d5\u05d5\u05d0\u05dc", + "\u05d6\u05d5 \u05d0\u05dc-QI'DAH", + "\u05d6\u05d5 \u05d0\u05dc-\u05d7\u05d9\u05d2\u05f3\u05d4", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "\u05e9\u05e0\u05ea \u05d4\u05d9\u05d2\u05f3\u05e8\u05d4", + } + }, + { "calendarname.islamic-civil", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9-\u05d0\u05d6\u05e8\u05d7\u05d9" }, + { "calendarname.islamicc", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9-\u05d0\u05d6\u05e8\u05d7\u05d9" }, + { "calendarname.islamic", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9" }, + { "calendarname.buddhist", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d1\u05d5\u05d3\u05d4\u05d9\u05e1\u05d8\u05d9" }, + { "calendarname.japanese", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d9\u05e4\u05e0\u05d9" }, + { "calendarname.gregorian", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d2\u05e8\u05d2\u05d5\u05e8\u05d9\u05d0\u05e0\u05d9" }, + { "calendarname.gregory", "\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d2\u05e8\u05d2\u05d5\u05e8\u05d9\u05d0\u05e0\u05d9" }, + { "field.era", "\u05ea\u05e7\u05d5\u05e4\u05d4" }, + { "field.year", "\u05e9\u05e0\u05d4" }, + { "field.month", "\u05d7\u05d5\u05d3\u05e9" }, + { "field.week", "\u05e9\u05d1\u05d5\u05e2" }, + { "field.weekday", "\u05d9\u05d5\u05dd \u05d1\u05e9\u05d1\u05d5\u05e2" }, + { "field.dayperiod", "\u05dc\u05e4\u05d4\u05f4\u05e6/\u05d0\u05d7\u05d4\u05f4\u05e6" }, + { "field.hour", "\u05e9\u05e2\u05d4" }, + { "field.minute", "\u05d3\u05e7\u05d4" }, + { "field.second", "\u05e9\u05e0\u05d9\u05d9\u05d4" }, + { "field.zone", "\u05d0\u05d6\u05d5\u05e8" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ja/FormatData_ja.java b/jdk/src/share/classes/sun/text/resources/ja/FormatData_ja.java index a45992952ea..cbff2411926 100644 --- a/jdk/src/share/classes/sun/text/resources/ja/FormatData_ja.java +++ b/jdk/src/share/classes/sun/text/resources/ja/FormatData_ja.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ja; import java.util.ListResourceBundle; @@ -133,6 +169,14 @@ public class FormatData_ja extends ListResourceBundle { "\u4ecf\u66a6", // Butsureki } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "Gy/MM/dd", + "Gy/MM/dd", + } + }, { "japanese.Eras", new String[] { // era strings for Japanese imperial calendar "\u897f\u66a6", // Seireki (Gregorian) @@ -183,6 +227,14 @@ public class FormatData_ja extends ListResourceBundle { "{1} {0}" // date-time pattern } }, + { "cldr.japanese.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy\u5e74M\u6708d\u65e5", + "Gyy/MM/dd", + } + }, { "japanese.DatePatterns", new String[] { "GGGGyyyy'\u5e74'M'\u6708'd'\u65e5'", // full date pattern @@ -205,6 +257,46 @@ public class FormatData_ja extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "roc.Eras", + new String[] { + "\u6c11\u56fd\u524d", + "\u6c11\u56fd", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/MM/dd", + "Gy/MM/dd", + } + }, + { "roc.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGy/MM/dd", + "GGGGy/MM/dd", + } + }, + { "calendarname.islamic-civil", "\u592a\u967d\u30a4\u30b9\u30e9\u30e0\u66a6" }, + { "calendarname.islamicc", "\u592a\u967d\u30a4\u30b9\u30e9\u30e0\u66a6" }, + { "calendarname.islamic", "\u30a4\u30b9\u30e9\u30e0\u66a6" }, + { "calendarname.japanese", "\u548c\u66a6" }, + { "calendarname.gregorian", "\u897f\u66a6[\u30b0\u30ec\u30b4\u30ea\u30aa\u66a6]" }, + { "calendarname.gregory", "\u897f\u66a6[\u30b0\u30ec\u30b4\u30ea\u30aa\u66a6]" }, + { "calendarname.roc", "\u4e2d\u83ef\u6c11\u56fd\u66a6" }, + { "calendarname.buddhist", "\u30bf\u30a4\u4ecf\u6559\u66a6" }, + { "field.era", "\u6642\u4ee3" }, + { "field.year", "\u5e74" }, + { "field.month", "\u6708" }, + { "field.week", "\u9031" }, + { "field.weekday", "\u66dc\u65e5" }, + { "field.dayperiod", "\u5348\u524d/\u5348\u5f8c" }, + { "field.hour", "\u6642" }, + { "field.minute", "\u5206" }, + { "field.second", "\u79d2" }, + { "field.zone", "\u30bf\u30a4\u30e0\u30be\u30fc\u30f3" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ko/FormatData_ko.java b/jdk/src/share/classes/sun/text/resources/ko/FormatData_ko.java index fc8badb82bf..6e1b3fba3f3 100644 --- a/jdk/src/share/classes/sun/text/resources/ko/FormatData_ko.java +++ b/jdk/src/share/classes/sun/text/resources/ko/FormatData_ko.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ko; import java.util.ListResourceBundle; @@ -143,6 +179,62 @@ public class FormatData_ko extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "G y\ub144 M\uc6d4 d\uc77c EEEE", + "G y\ub144 M\uc6d4 d\uc77c", + "G y. M. d", + "G y. M. d", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "G y\ub144 M\uc6d4 d\uc77c EEEE", + "G y\ub144 M\uc6d4 d\uc77c", + "G y. M. d", + "G y. M. d", + } + }, + { "roc.Eras", + new String[] { + "\uc911\ud654\ubbfc\uad6d\uc804", + "\uc911\ud654\ubbfc\uad6d", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "G y\ub144 M\uc6d4 d\uc77c EEEE", + "G y\ub144 M\uc6d4 d\uc77c", + "G y. M. d", + "G y. M. d", + } + }, + { "roc.DatePatterns", + new String[] { + "GGGG y\ub144 M\uc6d4 d\uc77c EEEE", + "GGGG y\ub144 M\uc6d4 d\uc77c", + "GGGG y. M. d", + "GGGG y. M. d", + } + }, + { "calendarname.islamic-civil", "\uc774\uc2ac\ub78c \uc0c1\uc6a9\ub825" }, + { "calendarname.islamicc", "\uc774\uc2ac\ub78c \uc0c1\uc6a9\ub825" }, + { "calendarname.islamic", "\uc774\uc2ac\ub78c\ub825" }, + { "calendarname.japanese", "\uc77c\ubcf8\ub825" }, + { "calendarname.gregorian", "\ud0dc\uc591\ub825" }, + { "calendarname.gregory", "\ud0dc\uc591\ub825" }, + { "calendarname.roc", "\ub300\ub9cc\ub825" }, + { "calendarname.buddhist", "\ubd88\uad50\ub825" }, + { "field.era", "\uc5f0\ud638" }, + { "field.year", "\ub144" }, + { "field.month", "\uc6d4" }, + { "field.week", "\uc8fc" }, + { "field.weekday", "\uc694\uc77c" }, + { "field.dayperiod", "\uc624\uc804/\uc624\ud6c4" }, + { "field.hour", "\uc2dc" }, + { "field.minute", "\ubd84" }, + { "field.second", "\ucd08" }, + { "field.zone", "\uc2dc\uac04\ub300" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/lt/FormatData_lt.java b/jdk/src/share/classes/sun/text/resources/lt/FormatData_lt.java index 9e949ecf563..90b740cd2e0 100644 --- a/jdk/src/share/classes/sun/text/resources/lt/FormatData_lt.java +++ b/jdk/src/share/classes/sun/text/resources/lt/FormatData_lt.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.lt; import java.util.ListResourceBundle; @@ -203,6 +239,32 @@ public class FormatData_lt extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "y G, MMMM d, EEEE", + "G y MMMM d", + "G y MMM d", + "GGGGG yyyy-MM-dd", + } + }, + { "calendarname.islamic-civil", "Pilietinis islamo kalendorius" }, + { "calendarname.islamicc", "Pilietinis islamo kalendorius" }, + { "calendarname.islamic", "Islamo kalendorius" }, + { "calendarname.japanese", "Japon\u0173 kalendorius" }, + { "calendarname.gregorian", "Grigaliaus kalendorius" }, + { "calendarname.gregory", "Grigaliaus kalendorius" }, + { "calendarname.roc", "Kinijos Respublikos kalendorius" }, + { "calendarname.buddhist", "Budist\u0173 kalendorius" }, + { "field.era", "era" }, + { "field.year", "metai" }, + { "field.month", "m\u0117nuo" }, + { "field.week", "savait\u0117" }, + { "field.weekday", "savait\u0117s diena" }, + { "field.dayperiod", "dienos metas" }, + { "field.hour", "valanda" }, + { "field.minute", "minut\u0117" }, + { "field.second", "sekund\u0117" }, + { "field.zone", "laiko juosta" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/lv/FormatData_lv.java b/jdk/src/share/classes/sun/text/resources/lv/FormatData_lv.java index ff9eb470d4b..208257a7638 100644 --- a/jdk/src/share/classes/sun/text/resources/lv/FormatData_lv.java +++ b/jdk/src/share/classes/sun/text/resources/lv/FormatData_lv.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.lv; import java.util.ListResourceBundle; @@ -175,6 +211,41 @@ public class FormatData_lv extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "islamic.MonthNames", + new String[] { + "muharams", + "safars", + "1. rab\u012b", + "2. rab\u012b", + "1. d\u017eum\u0101d\u0101", + "2. d\u017eum\u0101d\u0101", + "rad\u017eabs", + "\u0161abans", + "ramad\u0101ns", + "\u0161auvals", + "du al-kid\u0101", + "du al-hid\u017e\u0101", + "", + } + }, + { "calendarname.islamic-civil", "isl\u0101ma pilso\u0146u kalend\u0101rs" }, + { "calendarname.islamicc", "isl\u0101ma pilso\u0146u kalend\u0101rs" }, + { "calendarname.islamic", "isl\u0101ma kalend\u0101rs" }, + { "calendarname.japanese", "jap\u0101\u0146u kalend\u0101rs" }, + { "calendarname.gregorian", "Gregora kalend\u0101rs" }, + { "calendarname.gregory", "Gregora kalend\u0101rs" }, + { "calendarname.roc", "\u0136\u012bnas Republikas kalend\u0101rs" }, + { "calendarname.buddhist", "budistu kalend\u0101rs" }, + { "field.era", "\u0113ra" }, + { "field.year", "Gads" }, + { "field.month", "M\u0113nesis" }, + { "field.week", "Ned\u0113\u013ca" }, + { "field.weekday", "Ned\u0113\u013cas diena" }, + { "field.dayperiod", "Dayperiod" }, + { "field.hour", "Stundas" }, + { "field.minute", "Min\u016btes" }, + { "field.second", "Sekundes" }, + { "field.zone", "Josla" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/mk/FormatData_mk.java b/jdk/src/share/classes/sun/text/resources/mk/FormatData_mk.java index cd09d3ef1ee..1c7b8e0d9d4 100644 --- a/jdk/src/share/classes/sun/text/resources/mk/FormatData_mk.java +++ b/jdk/src/share/classes/sun/text/resources/mk/FormatData_mk.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.mk; import java.util.ListResourceBundle; @@ -158,6 +194,24 @@ public class FormatData_mk extends ListResourceBundle { } }, { "DateTimePatternChars", "GuMtkHmsSEDFwWahKzZ" }, + { "calendarname.islamic-civil", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0433\u0440\u0430\u0453\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamicc", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0433\u0440\u0430\u0453\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.roc", "\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u043d\u0430 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0430 \u041a\u0438\u043d\u0430" }, + { "calendarname.islamic", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.buddhist", "\u0411\u0443\u0434\u0438\u0441\u0442\u0438\u0447\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.japanese", "\u0408\u0430\u043f\u043e\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregorian", "\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregory", "\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "field.era", "\u0415\u0440\u0430" }, + { "field.year", "\u0433\u043e\u0434\u0438\u043d\u0430" }, + { "field.month", "\u041c\u0435\u0441\u0435\u0446" }, + { "field.week", "\u041d\u0435\u0434\u0435\u043b\u0430" }, + { "field.weekday", "\u0414\u0435\u043d \u0432\u043e \u043d\u0435\u0434\u0435\u043b\u0430\u0442\u0430" }, + { "field.dayperiod", "\u043f\u0440\u0435\u0442\u043f\u043b\u0430\u0434\u043d\u0435/\u043f\u043e\u043f\u043b\u0430\u0434\u043d\u0435" }, + { "field.hour", "\u0427\u0430\u0441" }, + { "field.minute", "\u041c\u0438\u043d\u0443\u0442\u0430" }, + { "field.second", "\u0421\u0435\u043a\u0443\u043d\u0434\u0430" }, + { "field.zone", "\u0437\u043e\u043d\u0430" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ms/FormatData_ms.java b/jdk/src/share/classes/sun/text/resources/ms/FormatData_ms.java index 13a8d51dd1d..78d0cb03dc6 100644 --- a/jdk/src/share/classes/sun/text/resources/ms/FormatData_ms.java +++ b/jdk/src/share/classes/sun/text/resources/ms/FormatData_ms.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. */ /* * COPYRIGHT AND PERMISSION NOTICE * - * Copyright (C) 1991-2007 Unicode, Inc. All rights reserved. - * Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of the Unicode data files and any associated documentation (the "Data @@ -14,10 +14,10 @@ * "Software") to deal in the Data Files or Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated * documentation, and (c) there is clear notice in each modified Data File or * in the Software as well as in the documentation associated with the Data * File(s) or Software that the data or software has been modified. @@ -27,19 +27,17 @@ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR - * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. * * Except as contained in this notice, the name of a copyright holder shall not * be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. */ -// Generated automatically from the Common Locale Data Repository. DO NOT EDIT! - package sun.text.resources.ms; import java.util.ListResourceBundle; @@ -191,6 +189,71 @@ public class FormatData_ms extends ListResourceBundle { "{1} {0}", } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d MMMM y G", + "d MMMM y G", + "dd/MM/y G", + "d/MM/y G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d MMMM y G", + "d MMMM y G", + "dd/MM/y G", + "d/MM/y G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d MMMM y G", + "d MMMM y G", + "dd/MM/y G", + "d/MM/y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d MMMM y GGGG", + "d MMMM y GGGG", + "dd/MM/y GGGG", + "d/MM/y GGGG", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, d MMMM y G", + "d MMMM y G", + "dd/MM/y G", + "d/MM/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, d MMMM y GGGG", + "d MMMM y GGGG", + "dd/MM/y GGGG", + "d/MM/y GGGG", + } + }, + { "calendarname.islamic-civil", "Kalendar Sivil Islam" }, + { "calendarname.islamicc", "Kalendar Sivil Islam" }, + { "calendarname.islamic", "Kalendar Islam" }, + { "calendarname.buddhist", "Kalendar Buddha" }, + { "calendarname.japanese", "Kalendar Jepun" }, + { "calendarname.roc", "Kalendar Minguo" }, + { "calendarname.gregorian", "Kalendar Gregory" }, + { "calendarname.gregory", "Kalendar Gregory" }, + { "field.year", "Tahun" }, + { "field.month", "Bulan" }, + { "field.week", "Minggu" }, + { "field.weekday", "Hari dalam Minggu" }, + { "field.dayperiod", "PG/PTG" }, + { "field.hour", "Jam" }, + { "field.minute", "Minit" }, + { "field.second", "Kedua" }, + { "field.zone", "Zon Waktu" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java b/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java index 4ef0957eba5..c702b6cdc9e 100644 --- a/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java +++ b/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. */ /* * COPYRIGHT AND PERMISSION NOTICE * - * Copyright (C) 1991-2007 Unicode, Inc. All rights reserved. - * Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of the Unicode data files and any associated documentation (the "Data @@ -14,10 +14,10 @@ * "Software") to deal in the Data Files or Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated * documentation, and (c) there is clear notice in each modified Data File or * in the Software as well as in the documentation associated with the Data * File(s) or Software that the data or software has been modified. @@ -27,19 +27,17 @@ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR - * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. * * Except as contained in this notice, the name of a copyright holder shall not * be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. */ -// Generated automatically from the Common Locale Data Repository. DO NOT EDIT! - package sun.text.resources.mt; import java.util.ListResourceBundle; @@ -169,6 +167,22 @@ public class FormatData_mt extends ListResourceBundle { "{1} {0}", } }, + { "calendarname.islamic-civil", "Kalendarju Islamiku-\u010aivili" }, + { "calendarname.islamicc", "Kalendarju Islamiku-\u010aivili" }, + { "calendarname.islamic", "Kalendarju Islamiku" }, + { "calendarname.buddhist", "Kalendarju Buddist" }, + { "calendarname.japanese", "Kalendarju \u0120appuni\u017c" }, + { "calendarname.gregorian", "Kalendarju Gregorjan" }, + { "calendarname.gregory", "Kalendarju Gregorjan" }, + { "field.era", "Epoka" }, + { "field.year", "Sena" }, + { "field.month", "Xahar" }, + { "field.week", "\u0120img\u0127a" }, + { "field.weekday", "Jum tal-\u0120img\u0127a" }, + { "field.hour", "Sieg\u0127a" }, + { "field.minute", "Minuta" }, + { "field.second", "Sekonda" }, + { "field.zone", "\u017bona" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/nl/FormatData_nl.java b/jdk/src/share/classes/sun/text/resources/nl/FormatData_nl.java index 78b937c2d64..5bc3964525c 100644 --- a/jdk/src/share/classes/sun/text/resources/nl/FormatData_nl.java +++ b/jdk/src/share/classes/sun/text/resources/nl/FormatData_nl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.nl; import java.util.ListResourceBundle; @@ -158,6 +194,111 @@ public class FormatData_nl extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "dd-MM-yy G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "dd-MM-yy GGGGG", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "dd-MM-yy GGGGG", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM y GGGG", + "dd-MM-yy G", + } + }, + { "islamic.MonthNames", + new String[] { + "Moeharram", + "Safar", + "Rabi\u02bba al awal", + "Rabi\u02bba al thani", + "Joemad\u02bbal awal", + "Joemad\u02bbal thani", + "Rajab", + "Sja\u02bbaban", + "Ramadan", + "Sjawal", + "Doe al ka\u02bbaba", + "Doe al hizja", + "", + } + }, + { "islamic.MonthAbbreviations", + new String[] { + "Moeh.", + "Saf.", + "Rab. I", + "Rab. II", + "Joem. I", + "Joem. II", + "Raj.", + "Sja.", + "Ram.", + "Sjaw.", + "Doe al k.", + "Doe al h.", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "Sa\u02bbna Hizjria", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "dd-MM-yy G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM y GGGG", + "dd-MM-yy GGGG", + } + }, + { "calendarname.islamic-civil", "Islamitische kalender (cyclisch)" }, + { "calendarname.islamicc", "Islamitische kalender (cyclisch)" }, + { "calendarname.roc", "Kalender van de Chinese Republiek" }, + { "calendarname.islamic", "Islamitische kalender" }, + { "calendarname.buddhist", "Boeddhistische kalender" }, + { "calendarname.japanese", "Japanse kalender" }, + { "calendarname.gregorian", "Gregoriaanse kalender" }, + { "calendarname.gregory", "Gregoriaanse kalender" }, + { "field.era", "Tijdperk" }, + { "field.year", "Jaar" }, + { "field.month", "Maand" }, + { "field.weekday", "Dag van de week" }, + { "field.dayperiod", "AM/PM" }, + { "field.hour", "Uur" }, + { "field.minute", "Minuut" }, + { "field.second", "Seconde" }, + { "field.zone", "Zone" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/pl/FormatData_pl.java b/jdk/src/share/classes/sun/text/resources/pl/FormatData_pl.java index 824645ef0db..630337d60fa 100644 --- a/jdk/src/share/classes/sun/text/resources/pl/FormatData_pl.java +++ b/jdk/src/share/classes/sun/text/resources/pl/FormatData_pl.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.pl; import java.util.ListResourceBundle; @@ -175,6 +211,71 @@ public class FormatData_pl extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "G y MMMM d", + "d MMM y G", + "dd.MM.yyyy G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM y G", + "dd.MM.yyyy G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM y G", + "dd.MM.yyyy G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d MMMM, y GGGG", + "d MMMM, y GGGG", + "d MMM y GGGG", + "dd.MM.yyyy GGGG", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, d MMMM, y G", + "d MMMM, y G", + "d MMM y G", + "dd.MM.yyyy G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, d MMMM, y GGGG", + "d MMMM, y GGGG", + "d MMM y GGGG", + "dd.MM.yyyy GGGG", + } + }, + { "calendarname.islamic-civil", "kalendarz islamski (metoda obliczeniowa)" }, + { "calendarname.islamicc", "kalendarz islamski (metoda obliczeniowa)" }, + { "calendarname.islamic", "kalendarz islamski (metoda wzrokowa)" }, + { "calendarname.japanese", "kalendarz japo\u0144ski" }, + { "calendarname.gregorian", "kalendarz gregoria\u0144ski" }, + { "calendarname.gregory", "kalendarz gregoria\u0144ski" }, + { "calendarname.roc", "kalendarz Republiki Chi\u0144skiej" }, + { "calendarname.buddhist", "kalendarz buddyjski" }, + { "field.era", "Era" }, + { "field.year", "Rok" }, + { "field.month", "Miesi\u0105c" }, + { "field.week", "Tydzie\u0144" }, + { "field.weekday", "Dzie\u0144 tygodnia" }, + { "field.hour", "Godzina" }, + { "field.minute", "Minuta" }, + { "field.second", "Sekunda" }, + { "field.zone", "Strefa" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/pt/FormatData_pt.java b/jdk/src/share/classes/sun/text/resources/pt/FormatData_pt.java index 4a0de29ad54..a9eae050312 100644 --- a/jdk/src/share/classes/sun/text/resources/pt/FormatData_pt.java +++ b/jdk/src/share/classes/sun/text/resources/pt/FormatData_pt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.pt; import java.util.ListResourceBundle; @@ -152,6 +188,64 @@ public class FormatData_pt extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "G y MMMM d", + "G y MMM d", + "d/M/yy", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/yyyy G", + "d/M/yyyy", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y GGGG", + "d 'de' MMMM 'de' y GGGG", + "dd/MM/yyyy GGGG", + "d/M/yyyy", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y G", + "d 'de' MMMM 'de' y G", + "dd/MM/yyyy G", + "d/M/yyyy", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, d 'de' MMMM 'de' y GGGG", + "d 'de' MMMM 'de' y GGGG", + "dd/MM/yyyy GGGG", + "d/M/yyyy", + } + }, + { "calendarname.islamic-civil", "Calend\u00e1rio Civil Isl\u00e2mico" }, + { "calendarname.islamicc", "Calend\u00e1rio Civil Isl\u00e2mico" }, + { "calendarname.islamic", "Calend\u00e1rio Isl\u00e2mico" }, + { "calendarname.japanese", "Calend\u00e1rio Japon\u00eas" }, + { "calendarname.gregorian", "Calend\u00e1rio Gregoriano" }, + { "calendarname.gregory", "Calend\u00e1rio Gregoriano" }, + { "calendarname.roc", "Calend\u00e1rio da Rep\u00fablica da China" }, + { "calendarname.buddhist", "Calend\u00e1rio Budista" }, + { "field.era", "Era" }, + { "field.year", "Ano" }, + { "field.month", "M\u00eas" }, + { "field.week", "Semana" }, + { "field.weekday", "Dia da semana" }, + { "field.dayperiod", "Per\u00edodo do dia" }, + { "field.hour", "Hora" }, + { "field.minute", "Minuto" }, + { "field.second", "Segundo" }, + { "field.zone", "Fuso" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ro/FormatData_ro.java b/jdk/src/share/classes/sun/text/resources/ro/FormatData_ro.java index c28502c1072..d1ab35ce523 100644 --- a/jdk/src/share/classes/sun/text/resources/ro/FormatData_ro.java +++ b/jdk/src/share/classes/sun/text/resources/ro/FormatData_ro.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ro; import java.util.ListResourceBundle; @@ -187,6 +223,32 @@ public class FormatData_ro extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, G y MMMM dd", + "d MMMM y G", + "d MMM y G", + "d/M/yyyy", + } + }, + { "calendarname.islamic-civil", "calendar islamic civil" }, + { "calendarname.islamicc", "calendar islamic civil" }, + { "calendarname.roc", "calendar al Republicii Chineze" }, + { "calendarname.islamic", "calendar islamic" }, + { "calendarname.buddhist", "calendar budist" }, + { "calendarname.japanese", "calendar japonez" }, + { "calendarname.gregorian", "calendar gregorian" }, + { "calendarname.gregory", "calendar gregorian" }, + { "field.era", "er\u0103" }, + { "field.year", "an" }, + { "field.month", "lun\u0103" }, + { "field.week", "s\u0103pt\u0103m\u00e2n\u0103" }, + { "field.weekday", "zi a s\u0103pt\u0103m\u00e2nii" }, + { "field.dayperiod", "perioada zilei" }, + { "field.hour", "or\u0103" }, + { "field.minute", "minut" }, + { "field.second", "secund\u0103" }, + { "field.zone", "zon\u0103" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/ru/FormatData_ru.java b/jdk/src/share/classes/sun/text/resources/ru/FormatData_ru.java index 820bf53497f..ba895954c0c 100644 --- a/jdk/src/share/classes/sun/text/resources/ru/FormatData_ru.java +++ b/jdk/src/share/classes/sun/text/resources/ru/FormatData_ru.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.ru; import java.util.ListResourceBundle; @@ -203,6 +239,88 @@ public class FormatData_ru extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. G", + "d MMMM y\u00a0'\u0433'. G", + "dd.MM.yyyy G", + "dd.MM.yy G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. G", + "d MMMM y\u00a0'\u0433'. G", + "dd.MM.yyyy G", + "dd.MM.yy G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. G", + "d MMMM y\u00a0'\u0433'. G", + "dd.MM.yyyy G", + "dd.MM.yy G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. GGGG", + "d MMMM y\u00a0'\u0433'. GGGG", + "dd.MM.yyyy GGGG", + "dd.MM.yy GGGG", + } + }, + { "islamic.MonthNames", + new String[] { + "\u041c\u0443\u0445\u0430\u0440\u0440\u0430\u043c", + "\u0421\u0430\u0444\u0430\u0440", + "\u0420\u0430\u0431\u0438-\u0443\u043b\u044c-\u0430\u0432\u0432\u0430\u043b\u044c", + "\u0420\u0430\u0431\u0438-\u0443\u043b\u044c-\u0430\u0445\u0438\u0440", + "\u0414\u0436\u0443\u043c\u0430\u0434-\u0443\u043b\u044c-\u0430\u0432\u0432\u0430\u043b\u044c", + "\u0414\u0436\u0443\u043c\u0430\u0434-\u0443\u043b\u044c-\u0430\u0445\u0438\u0440", + "\u0420\u0430\u0434\u0436\u0430\u0431", + "\u0428\u0430\u0430\u0431\u0430\u043d", + "\u0420\u0430\u043c\u0430\u0434\u0430\u043d", + "\u0428\u0430\u0432\u0432\u0430\u043b\u044c", + "\u0417\u0443\u043b\u044c-\u041a\u0430\u0430\u0434\u0430", + "\u0417\u0443\u043b\u044c-\u0425\u0438\u0434\u0436\u0436\u0430", + "", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. G", + "d MMMM y\u00a0'\u0433'. G", + "dd.MM.yyyy G", + "dd.MM.yy G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, d MMMM y\u00a0'\u0433'. GGGG", + "d MMMM y\u00a0'\u0433'. GGGG", + "dd.MM.yyyy GGGG", + "dd.MM.yy GGGG", + } + }, + { "calendarname.islamic-civil", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.islamicc", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.islamic", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.japanese", "\u042f\u043f\u043e\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.gregorian", "\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.gregory", "\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.roc", "\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "calendarname.buddhist", "\u0411\u0443\u0434\u0434\u0438\u0439\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c" }, + { "field.era", "\u042d\u0440\u0430" }, + { "field.year", "\u0413\u043e\u0434" }, + { "field.month", "\u041c\u0435\u0441\u044f\u0446" }, + { "field.week", "\u041d\u0435\u0434\u0435\u043b\u044f" }, + { "field.weekday", "\u0414\u0435\u043d\u044c \u043d\u0435\u0434\u0435\u043b\u0438" }, + { "field.hour", "\u0427\u0430\u0441" }, + { "field.minute", "\u041c\u0438\u043d\u0443\u0442\u0430" }, + { "field.second", "\u0421\u0435\u043a\u0443\u043d\u0434\u0430" }, + { "field.zone", "\u0427\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/sk/FormatData_sk.java b/jdk/src/share/classes/sun/text/resources/sk/FormatData_sk.java index 110985614a9..04f46e650ae 100644 --- a/jdk/src/share/classes/sun/text/resources/sk/FormatData_sk.java +++ b/jdk/src/share/classes/sun/text/resources/sk/FormatData_sk.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.sk; import java.util.ListResourceBundle; @@ -192,6 +228,23 @@ public class FormatData_sk extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "calendarname.islamic-civil", "Islamsk\u00fd ob\u010diansky kalend\u00e1r" }, + { "calendarname.islamicc", "Islamsk\u00fd ob\u010diansky kalend\u00e1r" }, + { "calendarname.islamic", "Islamsk\u00fd kalend\u00e1r" }, + { "calendarname.buddhist", "Buddhistick\u00fd kalend\u00e1r" }, + { "calendarname.japanese", "Japonsk\u00fd kalend\u00e1r" }, + { "calendarname.gregorian", "Gregori\u00e1nsky kalend\u00e1r" }, + { "calendarname.gregory", "Gregori\u00e1nsky kalend\u00e1r" }, + { "field.era", "\u00c9ra" }, + { "field.year", "Rok" }, + { "field.month", "Mesiac" }, + { "field.week", "T\u00fd\u017ede\u0148" }, + { "field.weekday", "De\u0148 v t\u00fd\u017edni" }, + { "field.dayperiod", "\u010cas\u0165 d\u0148a" }, + { "field.hour", "Hodina" }, + { "field.minute", "Min\u00fata" }, + { "field.second", "Sekunda" }, + { "field.zone", "P\u00e1smo" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/sl/FormatData_sl.java b/jdk/src/share/classes/sun/text/resources/sl/FormatData_sl.java index 34ce565af9c..864da47c77e 100644 --- a/jdk/src/share/classes/sun/text/resources/sl/FormatData_sl.java +++ b/jdk/src/share/classes/sun/text/resources/sl/FormatData_sl.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.sl; import java.util.ListResourceBundle; @@ -175,6 +211,24 @@ public class FormatData_sl extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "calendarname.islamic-civil", "islamski civilni koledar" }, + { "calendarname.islamicc", "islamski civilni koledar" }, + { "calendarname.roc", "kitajski dr\u017eavni koledar" }, + { "calendarname.islamic", "islamski koledar" }, + { "calendarname.buddhist", "budisti\u010dni koledar" }, + { "calendarname.japanese", "japonski koledar" }, + { "calendarname.gregorian", "gregorijanski koledar" }, + { "calendarname.gregory", "gregorijanski koledar" }, + { "field.era", "Doba" }, + { "field.year", "Leto" }, + { "field.month", "Mesec" }, + { "field.week", "Teden" }, + { "field.weekday", "Dan v tednu" }, + { "field.dayperiod", "\u010cas dneva" }, + { "field.hour", "Ura" }, + { "field.minute", "Minuta" }, + { "field.second", "Sekunda" }, + { "field.zone", "Obmo\u010dje" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/sr/FormatData_sr.java b/jdk/src/share/classes/sun/text/resources/sr/FormatData_sr.java index d331a8d9a3f..a190e09ac2a 100644 --- a/jdk/src/share/classes/sun/text/resources/sr/FormatData_sr.java +++ b/jdk/src/share/classes/sun/text/resources/sr/FormatData_sr.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. */ /* * COPYRIGHT AND PERMISSION NOTICE * - * Copyright (C) 1991-2007 Unicode, Inc. All rights reserved. - * Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of the Unicode data files and any associated documentation (the "Data @@ -14,10 +14,10 @@ * "Software") to deal in the Data Files or Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated * documentation, and (c) there is clear notice in each modified Data File or * in the Software as well as in the documentation associated with the Data * File(s) or Software that the data or software has been modified. @@ -27,19 +27,17 @@ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR - * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. * * Except as contained in this notice, the name of a copyright holder shall not * be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. */ -// Generated automatically from the Common Locale Data Repository. DO NOT EDIT! - package sun.text.resources.sr; import java.util.ListResourceBundle; @@ -176,6 +174,61 @@ public class FormatData_sr extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, MMMM d, y G", + "MMMM d, y G", + "MMM d, y G", + "M/d/yy G", + } + }, + { "roc.Eras", + new String[] { + "\u041f\u0440\u0435 \u0420\u041a", + "\u0420\u041a", + } + }, + { "islamic.MonthNames", + new String[] { + "\u041c\u0443\u0440\u0430\u0445\u0430\u043c", + "\u0421\u0430\u0444\u0430\u0440", + "\u0420\u0430\u0431\u0438\u02bb I", + "\u0420\u0430\u0431\u0438\u02bb II", + "\u0408\u0443\u043c\u0430\u0434\u0430 I", + "\u0408\u0443\u043c\u0430\u0434\u0430 II", + "\u0420\u0430\u0452\u0430\u0431", + "\u0428\u0430\u02bb\u0431\u0430\u043d", + "\u0420\u0430\u043c\u0430\u0434\u0430\u043d", + "\u0428\u0430\u0432\u0430\u043b", + "\u0414\u0443\u02bb\u043b-\u041a\u0438\u02bb\u0434\u0430", + "\u0414\u0443\u02bb\u043b-\u0445\u0438\u0452\u0430", + "", + } + }, + { "islamic.Eras", + new String[] { + "", + "\u0410\u0425", + } + }, + { "calendarname.islamic-civil", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u043d\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamicc", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u043d\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamic", "\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.japanese", "\u0408\u0430\u043f\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregorian", "\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregory", "\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.roc", "\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0435 \u041a\u0438\u043d\u0435" }, + { "calendarname.buddhist", "\u0411\u0443\u0434\u0438\u0441\u0442\u0438\u0447\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "field.era", "\u0435\u0440\u0430" }, + { "field.year", "\u0433\u043e\u0434\u0438\u043d\u0430" }, + { "field.month", "\u043c\u0435\u0441\u0435\u0446" }, + { "field.week", "\u043d\u0435\u0434\u0435\u0459\u0430" }, + { "field.weekday", "\u0434\u0430\u043d \u0443 \u043d\u0435\u0434\u0435\u0459\u0438" }, + { "field.dayperiod", "\u043f\u0440\u0435 \u043f\u043e\u0434\u043d\u0435/\u043f\u043e\u043f\u043e\u0434\u043d\u0435" }, + { "field.hour", "\u0447\u0430\u0441" }, + { "field.minute", "\u043c\u0438\u043d\u0443\u0442" }, + { "field.second", "\u0441\u0435\u043a\u0443\u043d\u0434" }, + { "field.zone", "\u0437\u043e\u043d\u0430" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/sv/FormatData_sv.java b/jdk/src/share/classes/sun/text/resources/sv/FormatData_sv.java index 7368a49c0ea..1d555e486da 100644 --- a/jdk/src/share/classes/sun/text/resources/sv/FormatData_sv.java +++ b/jdk/src/share/classes/sun/text/resources/sv/FormatData_sv.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.sv; import java.util.ListResourceBundle; @@ -198,6 +234,78 @@ public class FormatData_sv extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "G yyyy-MM-dd", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "G y-MM-dd", + } + }, + { "roc.Eras", + new String[] { + "f\u00f6re R.K.", + "R.K.", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "G y-MM-dd", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM y GGGG", + "GGGG y-MM-dd", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE d MMMM y G", + "d MMMM y G", + "d MMM y G", + "G y-MM-dd", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE d MMMM y GGGG", + "d MMMM y GGGG", + "d MMM y GGGG", + "GGGG y-MM-dd", + } + }, + { "calendarname.islamic-civil", "islamisk civil kalender" }, + { "calendarname.islamicc", "islamisk civil kalender" }, + { "calendarname.islamic", "islamisk kalender" }, + { "calendarname.japanese", "japansk kalender" }, + { "calendarname.gregorian", "gregoriansk kalender" }, + { "calendarname.gregory", "gregoriansk kalender" }, + { "calendarname.roc", "kinesiska republikens kalender" }, + { "calendarname.buddhist", "buddistisk kalender" }, + { "field.era", "era" }, + { "field.year", "\u00e5r" }, + { "field.month", "m\u00e5nad" }, + { "field.week", "vecka" }, + { "field.weekday", "veckodag" }, + { "field.dayperiod", "fm/em" }, + { "field.hour", "timme" }, + { "field.minute", "minut" }, + { "field.second", "sekund" }, + { "field.zone", "tidszon" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/th/FormatData_th.java b/jdk/src/share/classes/sun/text/resources/th/FormatData_th.java index bec15d10191..aa6bd7fa10a 100644 --- a/jdk/src/share/classes/sun/text/resources/th/FormatData_th.java +++ b/jdk/src/share/classes/sun/text/resources/th/FormatData_th.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.th; import java.util.ListResourceBundle; @@ -182,6 +218,14 @@ public class FormatData_th extends ListResourceBundle { { "buddhist.TimePatterns", timePatterns }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE\u0e17\u0e35\u0e48 d MMMM G y", + "d MMMM y", + "d MMM y", + "d/M/yyyy", + } + }, { "buddhist.DatePatterns", datePatterns }, @@ -198,6 +242,77 @@ public class FormatData_th extends ListResourceBundle { dateTimePatterns }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE\u0e17\u0e35\u0e48 d MMMM \u0e1b\u0e35G\u0e17\u0e35\u0e48 y", + "d MMMM \u0e1b\u0e35G y", + "d MMM G y", + "d/M/yy", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE\u0e17\u0e35\u0e48 d MMMM \u0e1b\u0e35G\u0e17\u0e35\u0e48 y", + "d MMMM \u0e1b\u0e35G y", + "d MMM G y", + "d/M/yy", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE\u0e17\u0e35\u0e48 d MMMM \u0e1b\u0e35GGGG\u0e17\u0e35\u0e48 y", + "d MMMM \u0e1b\u0e35GGGG y", + "d MMM GGGG y", + "d/M/yy", + } + }, + { "islamic.MonthNames", + new String[] { + "\u0e21\u0e38\u0e2e\u0e30\u0e23\u0e4c\u0e23\u0e2d\u0e21", + "\u0e0b\u0e2d\u0e1f\u0e32\u0e23\u0e4c", + "\u0e23\u0e2d\u0e1a\u0e35 I", + "\u0e23\u0e2d\u0e1a\u0e35 II", + "\u0e08\u0e38\u0e21\u0e32\u0e14\u0e32 I", + "\u0e08\u0e38\u0e21\u0e32\u0e14\u0e32 II", + "\u0e23\u0e2d\u0e08\u0e31\u0e1a", + "\u0e0a\u0e30\u0e2d\u0e30\u0e1a\u0e32\u0e19", + "\u0e23\u0e2d\u0e21\u0e30\u0e14\u0e2d\u0e19", + "\u0e40\u0e0a\u0e32\u0e27\u0e31\u0e25", + "\u0e14\u0e2e\u0e38\u0e38\u0e2d\u0e31\u0e25\u0e01\u0e34\u0e14\u0e30\u0e2b\u0e4c", + "\u0e14\u0e2e\u0e38\u0e2d\u0e31\u0e25\u0e2e\u0e34\u0e08\u0e08\u0e30\u0e2b\u0e4c", + "", + } + }, + { "islamic.long.Eras", + new String[] { + "", + "\u0e2e\u0e34\u0e08\u0e40\u0e23\u0e32\u0e30\u0e2b\u0e4c\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a", + } + }, + { "islamic.Eras", + new String[] { + "", + "\u0e2e.\u0e28.", + } + }, + { "calendarname.islamic-civil", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21\u0e0b\u0e35\u0e27\u0e34\u0e25" }, + { "calendarname.islamicc", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21\u0e0b\u0e35\u0e27\u0e34\u0e25" }, + { "calendarname.islamic", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21" }, + { "calendarname.japanese", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e0d\u0e35\u0e48\u0e1b\u0e38\u0e48\u0e19" }, + { "calendarname.gregorian", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e40\u0e01\u0e23\u0e01\u0e2d\u0e40\u0e23\u0e35\u0e22\u0e19" }, + { "calendarname.gregory", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e40\u0e01\u0e23\u0e01\u0e2d\u0e40\u0e23\u0e35\u0e22\u0e19" }, + { "calendarname.roc", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e44\u0e15\u0e49\u0e2b\u0e27\u0e31\u0e19" }, + { "calendarname.buddhist", "\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e1e\u0e38\u0e17\u0e18" }, + { "field.era", "\u0e2a\u0e21\u0e31\u0e22" }, + { "field.year", "\u0e1b\u0e35" }, + { "field.month", "\u0e40\u0e14\u0e37\u0e2d\u0e19" }, + { "field.week", "\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c" }, + { "field.weekday", "\u0e27\u0e31\u0e19\u0e43\u0e19\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c" }, + { "field.dayperiod", "\u0e0a\u0e48\u0e27\u0e07\u0e27\u0e31\u0e19" }, + { "field.hour", "\u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07" }, + { "field.minute", "\u0e19\u0e32\u0e17\u0e35" }, + { "field.second", "\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35" }, + { "field.zone", "\u0e40\u0e02\u0e15" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/tr/FormatData_tr.java b/jdk/src/share/classes/sun/text/resources/tr/FormatData_tr.java index 2be1b12f588..c8fc0f540e9 100644 --- a/jdk/src/share/classes/sun/text/resources/tr/FormatData_tr.java +++ b/jdk/src/share/classes/sun/text/resources/tr/FormatData_tr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.tr; import java.util.ListResourceBundle; @@ -176,6 +212,89 @@ public class FormatData_tr extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "dd MMMM y G EEEE", + "dd MMMM y G", + "dd MMM y G", + "dd.MM.yyyy G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "dd MMMM y G EEEE", + "dd MMMM y G", + "dd MMM y G", + "dd.MM.yyyy G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "dd MMMM y G EEEE", + "dd MMMM y G", + "dd MMM y G", + "dd.MM.yyyy G", + } + }, + { "roc.DatePatterns", + new String[] { + "dd MMMM y GGGG EEEE", + "dd MMMM y GGGG", + "dd MMM y GGGG", + "dd.MM.yyyy GGGG", + } + }, + { "islamic.MonthNames", + new String[] { + "Muharrem", + "Safer", + "Rebi\u00fclevvel", + "Rebi\u00fclahir", + "Cemaziyelevvel", + "Cemaziyelahir", + "Recep", + "\u015eaban", + "Ramazan", + "\u015eevval", + "Zilkade", + "Zilhicce", + "", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "dd MMMM y G EEEE", + "dd MMMM y G", + "dd MMM y G", + "dd.MM.yyyy G", + } + }, + { "islamic.DatePatterns", + new String[] { + "dd MMMM y GGGG EEEE", + "dd MMMM y GGGG", + "dd MMM y GGGG", + "dd.MM.yyyy GGGG", + } + }, + { "calendarname.islamic-civil", "Arap Takvimi" }, + { "calendarname.islamicc", "Arap Takvimi" }, + { "calendarname.islamic", "Hicri Takvim" }, + { "calendarname.japanese", "Japon Takvimi" }, + { "calendarname.gregorian", "Miladi Takvim" }, + { "calendarname.gregory", "Miladi Takvim" }, + { "calendarname.roc", "\u00c7in Cumhuriyeti Takvimi" }, + { "calendarname.buddhist", "Budist Takvimi" }, + { "field.era", "Miladi D\u00f6nem" }, + { "field.year", "Y\u0131l" }, + { "field.month", "Ay" }, + { "field.week", "Hafta" }, + { "field.weekday", "Haftan\u0131n G\u00fcn\u00fc" }, + { "field.dayperiod", "AM/PM" }, + { "field.hour", "Saat" }, + { "field.minute", "Dakika" }, + { "field.second", "Saniye" }, + { "field.zone", "Saat Dilimi" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/uk/FormatData_uk.java b/jdk/src/share/classes/sun/text/resources/uk/FormatData_uk.java index 7aa0e0c451b..1d896f6dad4 100644 --- a/jdk/src/share/classes/sun/text/resources/uk/FormatData_uk.java +++ b/jdk/src/share/classes/sun/text/resources/uk/FormatData_uk.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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.uk; import java.util.ListResourceBundle; @@ -192,6 +228,41 @@ public class FormatData_uk extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "islamic.MonthNames", + new String[] { + "\u041c\u0443\u0445\u0430\u0440\u0440\u0430\u043c", + "\u0421\u0430\u0444\u0430\u0440", + "\u0420\u0430\u0431\u0456 I", + "\u0420\u0430\u0431\u0456 II", + "\u0414\u0436\u0443\u043c\u0430\u0434\u0430 I", + "\u0414\u0436\u0443\u043c\u0430\u0434\u0430 II", + "\u0420\u0430\u0434\u0436\u0430\u0431", + "\u0428\u0430\u0430\u0431\u0430\u043d", + "\u0420\u0430\u043c\u0430\u0434\u0430\u043d", + "\u0414\u0430\u0432\u0432\u0430\u043b", + "\u0417\u0443-\u043b\u044c-\u043a\u0430\u0430\u0434\u0430", + "\u0417\u0443-\u043b\u044c-\u0445\u0456\u0434\u0436\u0430", + "", + } + }, + { "calendarname.islamic-civil", "\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u0441\u0432\u0456\u0442\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamicc", "\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u0441\u0432\u0456\u0442\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.islamic", "\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.japanese", "\u042f\u043f\u043e\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregorian", "\u0413\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.gregory", "\u0413\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "calendarname.roc", "\u041a\u0438\u0442\u0430\u0439\u0441\u044c\u043a\u0438\u0439 \u0433\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439" }, + { "calendarname.buddhist", "\u0411\u0443\u0434\u0434\u0456\u0439\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440" }, + { "field.era", "\u0415\u0440\u0430" }, + { "field.year", "\u0420\u0456\u043a" }, + { "field.month", "\u041c\u0456\u0441\u044f\u0446\u044c" }, + { "field.week", "\u0422\u0438\u0436\u0434\u0435\u043d\u044c" }, + { "field.weekday", "\u0414\u0435\u043d\u044c \u0442\u0438\u0436\u043d\u044f" }, + { "field.dayperiod", "\u0427\u0430\u0441\u0442\u0438\u043d\u0430 \u0434\u043e\u0431\u0438" }, + { "field.hour", "\u0413\u043e\u0434\u0438\u043d\u0430" }, + { "field.minute", "\u0425\u0432\u0438\u043b\u0438\u043d\u0430" }, + { "field.second", "\u0421\u0435\u043a\u0443\u043d\u0434\u0430" }, + { "field.zone", "\u0417\u043e\u043d\u0430" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/vi/FormatData_vi.java b/jdk/src/share/classes/sun/text/resources/vi/FormatData_vi.java index fd892d96606..c0d1f2dd250 100644 --- a/jdk/src/share/classes/sun/text/resources/vi/FormatData_vi.java +++ b/jdk/src/share/classes/sun/text/resources/vi/FormatData_vi.java @@ -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 @@ -40,6 +40,42 @@ * http://oss.software.ibm.com/cvs/icu/icu/source/data/locales/vi.txt?rev=1.38 */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.vi; import java.util.ListResourceBundle; @@ -165,6 +201,72 @@ public class FormatData_vi extends ListResourceBundle { "{0} {1}" // date-time pattern } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y G", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y G", + "dd-MM-yyyy G", + "dd/MM/yyyy G", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y G", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y G", + "dd-MM-y G", + "dd/MM/y G", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y G", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y G", + "dd-MM-y G", + "dd/MM/y G", + } + }, + { "roc.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y GGGG", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y GGGG", + "dd-MM-y GGGG", + "dd/MM/y GGGG", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y G", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y G", + "dd-MM-y G", + "dd/MM/y G", + } + }, + { "islamic.DatePatterns", + new String[] { + "EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y GGGG", + "'Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y GGGG", + "dd-MM-y GGGG", + "dd/MM/y GGGG", + } + }, + { "calendarname.islamic-civil", "L\u1ecbch Islamic-Civil" }, + { "calendarname.islamicc", "L\u1ecbch Islamic-Civil" }, + { "calendarname.islamic", "L\u1ecbch Islamic" }, + { "calendarname.buddhist", "L\u1ecbch Ph\u1eadt Gi\u00e1o" }, + { "calendarname.japanese", "L\u1ecbch Nh\u1eadt B\u1ea3n" }, + { "calendarname.roc", "L\u1ecbch Trung Hoa D\u00e2n Qu\u1ed1c" }, + { "calendarname.gregorian", "L\u1ecbch Gregory" }, + { "calendarname.gregory", "L\u1ecbch Gregory" }, + { "field.era", "Th\u1eddi \u0111\u1ea1i" }, + { "field.year", "N\u0103m" }, + { "field.month", "Th\u00e1ng" }, + { "field.week", "Tu\u1ea7n" }, + { "field.weekday", "Ng\u00e0y trong tu\u1ea7n" }, + { "field.dayperiod", "SA/CH" }, + { "field.hour", "Gi\u1edd" }, + { "field.minute", "Ph\u00fat" }, + { "field.second", "Gi\u00e2y" }, + { "field.zone", "M\u00fai gi\u1edd" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java b/jdk/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java index c8eeba7e1ec..6cf5b0dd62b 100644 --- a/jdk/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java +++ b/jdk/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java @@ -47,12 +47,13 @@ import java.util.ListResourceBundle; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; public class CollationData_zh_HK extends ListResourceBundle { // reparent to zh_TW for traditional Chinese collation sequence public CollationData_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCollationData(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCollationData(Locale.TAIWAN); setParent(bundle); } diff --git a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh.java b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh.java index 57dbe2a0c61..8e7da48f655 100644 --- a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh.java +++ b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.zh; import java.util.ListResourceBundle; @@ -165,6 +201,78 @@ public class FormatData_zh extends ListResourceBundle { "{1} {0}" // date-time pattern } }, + { "cldr.buddhist.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gyyyy-M-d", + "Gy-M-d", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy\u5e74M\u6708d\u65e5", + "Gyy-MM-dd", + } + }, + { "roc.Eras", + new String[] { + "\u6c11\u56fd\u524d", + "\u6c11\u56fd", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy-M-d", + "Gy-M-d", + } + }, + { "roc.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGy-M-d", + "GGGGy-M-d", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy\u5e74M\u6708d\u65e5", + "Gyy-MM-dd", + } + }, + { "islamic.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGyy-MM-dd", + } + }, + { "calendarname.islamic-civil", "\u4f0a\u65af\u5170\u5e0c\u5409\u6765\u5386" }, + { "calendarname.islamicc", "\u4f0a\u65af\u5170\u5e0c\u5409\u6765\u5386" }, + { "calendarname.islamic", "\u4f0a\u65af\u5170\u65e5\u5386" }, + { "calendarname.japanese", "\u65e5\u672c\u65e5\u5386" }, + { "calendarname.gregorian", "\u516c\u5386" }, + { "calendarname.gregory", "\u516c\u5386" }, + { "calendarname.roc", "\u6c11\u56fd\u65e5\u5386" }, + { "calendarname.buddhist", "\u4f5b\u6559\u65e5\u5386" }, + { "field.era", "\u65f6\u671f" }, + { "field.year", "\u5e74" }, + { "field.month", "\u6708" }, + { "field.week", "\u5468" }, + { "field.weekday", "\u5468\u5929" }, + { "field.dayperiod", "\u4e0a\u5348/\u4e0b\u5348" }, + { "field.hour", "\u5c0f\u65f6" }, + { "field.minute", "\u5206\u949f" }, + { "field.second", "\u79d2\u949f" }, + { "field.zone", "\u533a\u57df" }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java index 9e2fd3383c8..23c3f6e43fe 100644 --- a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java +++ b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java @@ -44,12 +44,14 @@ import java.util.ListResourceBundle; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; public class FormatData_zh_HK extends ListResourceBundle { // reparent to zh_TW for traditional Chinese names public FormatData_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()) + .getLocaleData().getDateFormatData(Locale.TAIWAN); setParent(bundle); } diff --git a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_TW.java b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_TW.java index 33c356a04ec..c7fef5e8265 100644 --- a/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_TW.java +++ b/jdk/src/share/classes/sun/text/resources/zh/FormatData_zh_TW.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, 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 @@ -38,6 +38,42 @@ * */ +/* + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (C) 1991-2012 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do so, + * provided that (a) the above copyright notice(s) and this permission notice + * appear with all copies of the Data Files or Software, (b) both the above + * copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written authorization + * of the copyright holder. + */ + package sun.text.resources.zh; import java.util.ListResourceBundle; @@ -83,6 +119,77 @@ public class FormatData_zh_TW extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, + { "cldr.buddhist.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/M/d", + "Gy/M/d", + } + }, + { "cldr.japanese.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/M/d", + "Gy/M/d", + } + }, + { "roc.Eras", + new String[] { + "\u6c11\u570b\u524d", + "\u6c11\u570b", + } + }, + { "cldr.roc.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/M/d", + "Gy/M/d", + } + }, + { "roc.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGy/M/d", + "GGGGy/M/d", + } + }, + { "cldr.islamic.DatePatterns", + new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/M/d", + "Gy/M/d", + } + }, + { "islamic.DatePatterns", + new String[] { + "GGGGy\u5e74M\u6708d\u65e5EEEE", + "GGGGy\u5e74M\u6708d\u65e5", + "GGGGy/M/d", + "GGGGy/M/d", + } + }, + { "calendarname.islamic-civil", "\u4f0a\u65af\u862d\u57ce\u5e02\u66c6\u6cd5" }, + { "calendarname.islamicc", "\u4f0a\u65af\u862d\u57ce\u5e02\u66c6\u6cd5" }, + { "calendarname.islamic", "\u4f0a\u65af\u862d\u66c6\u6cd5" }, + { "calendarname.japanese", "\u65e5\u672c\u66c6\u6cd5" }, + { "calendarname.gregorian", "\u516c\u66c6" }, + { "calendarname.gregory", "\u516c\u66c6" }, + { "calendarname.roc", "\u6c11\u570b\u66c6" }, + { "calendarname.buddhist", "\u4f5b\u6559\u66c6\u6cd5" }, + { "field.era", "\u5e74\u4ee3" }, + { "field.year", "\u5e74" }, + { "field.month", "\u6708" }, + { "field.week", "\u9031" }, + { "field.weekday", "\u9031\u5929" }, + { "field.dayperiod", "\u4e0a\u5348/\u4e0b\u5348" }, + { "field.hour", "\u5c0f\u6642" }, + { "field.minute", "\u5206\u9418" }, + { "field.second", "\u79d2" }, }; } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java b/jdk/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java index a68a8ba956d..78edef1b7c0 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java +++ b/jdk/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java @@ -43,7 +43,6 @@ import java.util.spi.CurrencyNameProvider; import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; -import sun.util.resources.LocaleData; /** * An abstract parent class for the @@ -146,11 +145,6 @@ public abstract class AuxLocaleProviderAdapter extends LocaleProviderAdapter { return null; } - @Override - public LocaleData getLocaleData() { - return null; - } - private static Locale[] availableLocales = null; @Override diff --git a/jdk/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java index 35a8a7c1f33..1a611a087e1 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java @@ -25,12 +25,12 @@ package sun.util.locale.provider; +import java.io.IOException; import java.text.BreakIterator; import java.text.spi.BreakIteratorProvider; import java.util.Locale; -import java.util.ResourceBundle; +import java.util.MissingResourceException; import java.util.Set; -import sun.util.resources.LocaleData; /** * Concrete implementation of the {@link java.text.spi.BreakIteratorProvider @@ -159,24 +159,22 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider throw new NullPointerException(); } - ResourceBundle bundle = LocaleData.getBundle( - LocaleProviderAdapter.Type.JRE.getTextResourcesPackage() + ".BreakIteratorInfo", locale); - String[] classNames = bundle.getStringArray("BreakIteratorClasses"); - - String dataFile = bundle.getString(dataName); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale); + String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses"); + String dataFile = (String) lr.getBreakIteratorInfo(dataName); try { switch (classNames[type]) { case "RuleBasedBreakIterator": return new RuleBasedBreakIterator(dataFile); case "DictionaryBasedBreakIterator": - String dictionaryFile = bundle.getString(dictionaryName); + String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName); return new DictionaryBasedBreakIterator(dataFile, dictionaryFile); default: throw new IllegalArgumentException("Invalid break iterator class \"" + classNames[type] + "\""); } - } catch (Exception e) { + } catch (IOException | MissingResourceException | IllegalArgumentException e) { throw new InternalError(e.toString(), e); } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java index 16d08b3cbe3..136889fbd58 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java @@ -24,10 +24,7 @@ */ package sun.util.locale.provider; -import java.util.Calendar; -import static java.util.Calendar.*; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.CalendarDataProvider; @@ -49,12 +46,14 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av @Override public int getFirstDayOfWeek(Locale locale) { - return getIntData(CalendarDataUtility.FIRST_DAY_OF_WEEK, locale); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + .getCalendarData(CalendarDataUtility.FIRST_DAY_OF_WEEK); } @Override public int getMinimalDaysInFirstWeek(Locale locale) { - return getIntData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK, locale); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + .getCalendarData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK); } @Override @@ -66,13 +65,4 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av public Set getAvailableLanguageTags() { return langtags; } - - private int getIntData(String key, Locale locale) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); - if (rb.containsKey(key)) { - String firstday = rb.getString(key); - return Integer.parseInt(firstday); - } - return 0; - } } 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 f181c98d655..5b11c6cd9ac 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java @@ -65,14 +65,27 @@ public class CalendarDataUtility { public static String retrieveFieldValueName(String id, int field, int value, int style, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); - return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, id, + return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), field, value, style); } public static Map retrieveFieldValueNames(String id, int field, int style, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); - return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, id, field, style); + return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, + normalizeCalendarType(id), field, style); + } + + private static String normalizeCalendarType(String requestID) { + String type; + if (requestID.equals("gregorian") || requestID.equals("iso8601")) { + type = "gregory"; + } else if (requestID.startsWith("islamic")) { + type = "islamic"; + } else { + type = requestID; + } + return type; } /** 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 20be38607f8..6aa2893e173 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.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 @@ -28,7 +28,6 @@ import static java.util.Calendar.*; import java.util.Comparator; import java.util.Locale; import java.util.Map; -import java.util.ResourceBundle; import java.util.Set; import java.util.TreeMap; import java.util.spi.CalendarNameProvider; @@ -54,22 +53,19 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av String name = null; String key = getResourceKey(calendarType, field, style); if (key != null) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); - if (rb.containsKey(key)) { - String[] strings = rb.getStringArray(key); - if (strings.length > 0) { - if (field == DAY_OF_WEEK || field == YEAR) { - --value; - } - name = strings[value]; - // If name is empty in standalone, try its `format' style. - if (name.length() == 0 - && (style == SHORT_STANDALONE || style == LONG_STANDALONE - || style == NARROW_STANDALONE)) { - name = getDisplayName(calendarType, field, value, - getBaseStyle(style), - locale); - } + String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); + if (strings != null && strings.length > 0) { + if (field == DAY_OF_WEEK || field == YEAR) { + --value; + } + name = strings[value]; + // If name is empty in standalone, try its `format' style. + if (name.length() == 0 + && (style == SHORT_STANDALONE || style == LONG_STANDALONE + || style == NARROW_STANDALONE)) { + name = getDisplayName(calendarType, field, value, + getBaseStyle(style), + locale); } } } @@ -100,9 +96,8 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av String key = getResourceKey(calendarType, field, style); Map map = new TreeMap<>(LengthBasedComparator.INSTANCE); if (key != null) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); - if (rb.containsKey(key)) { - String[] strings = rb.getStringArray(key); + String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); + if (strings != null) { if (!hasDuplicates(strings)) { if (field == YEAR) { if (strings.length > 0) { @@ -168,6 +163,8 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av case "buddhist": case "japanese": case "gregory": + case "islamic": + case "roc": break; default: // Unknown calendar type @@ -244,6 +241,9 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av break; case MONTH: + if ("islamic".equals(type)) { + key.append(type).append('.'); + } if (isStandalone) { key.append("standalone."); } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java index ba9ba7be644..3f997cf9b40 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java @@ -45,8 +45,6 @@ import java.text.ParseException; import java.text.RuleBasedCollator; import java.text.spi.CollatorProvider; import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import java.util.Set; /** @@ -102,14 +100,7 @@ public class CollatorProviderImpl extends CollatorProvider implements AvailableL // Load the resource of the desired locale from resource // manager. - String colString = ""; - try { - ResourceBundle resource = LocaleProviderAdapter.forType(type).getLocaleData().getCollationData(locale); - - colString = resource.getString("Rule"); - } catch (MissingResourceException e) { - // Use default values - } + String colString = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCollationData(); try { result = new RuleBasedCollator(CollationRules.DEFAULTRULES + diff --git a/jdk/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java index cfa805fddfc..6e368bca85f 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java @@ -26,7 +26,6 @@ package sun.util.locale.provider; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.CurrencyNameProvider; @@ -120,11 +119,6 @@ public class CurrencyNameProviderImpl extends CurrencyNameProvider throw new NullPointerException(); } - ResourceBundle bundle = LocaleProviderAdapter.forType(type).getLocaleData().getCurrencyNames(locale); - if (bundle.containsKey(key)) { - return bundle.getString(key); - } - - return null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCurrencyName(key); } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 9f86f7a35ab..cd33bc2140d 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -54,7 +54,7 @@ import sun.util.resources.LocaleData; * @author Naoto Sato * @author Masayoshi Okutsu */ -public class JRELocaleProviderAdapter extends LocaleProviderAdapter { +public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter { private static final String LOCALE_DATA_JAR_NAME = "localedata.jar"; @@ -296,6 +296,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter { return lr; } + // ResourceBundleBasedAdapter method implementation @Override public LocaleData getLocaleData() { if (localeData == null) { diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java index 952078fd5c3..16f71b1158e 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java @@ -26,7 +26,6 @@ package sun.util.locale.provider; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.LocaleNameProvider; @@ -174,12 +173,7 @@ public class LocaleNameProviderImpl extends LocaleNameProvider implements Availa throw new NullPointerException(); } - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getLocaleNames(locale); - if (rb.containsKey(key)) { - return rb.getString(key); - } - - return null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getLocaleName(key); } @Override diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 17f5c0999d5..2f12f6540ce 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -37,6 +37,8 @@ import java.util.List; import java.util.Locale; import java.util.ResourceBundle; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.spi.CalendarDataProvider; import java.util.spi.CalendarNameProvider; import java.util.spi.CurrencyNameProvider; @@ -44,7 +46,6 @@ import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; import sun.util.cldr.CLDRLocaleProviderAdapter; -import sun.util.resources.LocaleData; /** * The LocaleProviderAdapter abstract class. @@ -119,6 +120,12 @@ public abstract class LocaleProviderAdapter { */ private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null; + /** + * Adapter lookup cache. + */ + private static ConcurrentMap, ConcurrentMap> + adapterCache = new ConcurrentHashMap<>(); + static { String order = AccessController.doPrivileged( new sun.security.action.GetPropertyAction("java.locale.providers")); @@ -210,9 +217,23 @@ public abstract class LocaleProviderAdapter { */ public static LocaleProviderAdapter getAdapter(Class providerClass, Locale locale) { + LocaleProviderAdapter adapter; + + // cache lookup + ConcurrentMap adapterMap = adapterCache.get(providerClass); + if (adapterMap != null) { + if ((adapter = adapterMap.get(locale)) != null) { + return adapter; + } + } else { + adapterMap = new ConcurrentHashMap<>(); + adapterCache.putIfAbsent(providerClass, adapterMap); + } + // Fast look-up for the given locale - LocaleProviderAdapter adapter = findAdapter(providerClass, locale); + adapter = findAdapter(providerClass, locale); if (adapter != null) { + adapterMap.putIfAbsent(locale, adapter); return adapter; } @@ -226,11 +247,13 @@ public abstract class LocaleProviderAdapter { } adapter = findAdapter(providerClass, loc); if (adapter != null) { + adapterMap.putIfAbsent(locale, adapter); return adapter; } } // returns the adapter for FALLBACK as the last resort + adapterMap.putIfAbsent(locale, fallbackLocaleProviderAdapter); return fallbackLocaleProviderAdapter; } @@ -398,7 +421,5 @@ public abstract class LocaleProviderAdapter { public abstract LocaleResources getLocaleResources(Locale locale); - public abstract LocaleData getLocaleData(); - public abstract Locale[] getAvailableLocales(); } 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 ff389f61b35..009cc5b8a63 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.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 @@ -40,43 +40,295 @@ package sun.util.locale.provider; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.util.Calendar; +import java.util.LinkedHashSet; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.util.calendar.ZoneInfo; +import sun.util.resources.LocaleData; +import sun.util.resources.OpenListResourceBundle; import sun.util.resources.TimeZoneNamesBundle; /** - * Central accessor to locale-dependent resources. + * Central accessor to locale-dependent resources for JRE/CLDR provider adapters. * * @author Masayoshi Okutsu + * @author Naoto Sato */ public class LocaleResources { - private final LocaleProviderAdapter adapter; private final Locale locale; + private final LocaleData localeData; + private final LocaleProviderAdapter.Type type; // Resource cache - private ConcurrentMap cache = new ConcurrentHashMap<>(); + private ConcurrentMap cache = new ConcurrentHashMap<>(); + private ReferenceQueue referenceQueue = new ReferenceQueue<>(); + // cache key prefixes + private static final String BREAK_ITERATOR_INFO = "BII."; + private static final String CALENDAR_DATA = "CALD."; + private static final String COLLATION_DATA_CACHEKEY = "COLD"; + private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD"; + private static final String CURRENCY_NAMES = "CN."; + private static final String LOCALE_NAMES = "LN."; + private static final String TIME_ZONE_NAMES = "TZN."; + private static final String ZONE_IDS_CACHEKEY = "ZID"; + private static final String CALENDAR_NAMES = "CALN."; + private static final String NUMBER_PATTERNS_CACHEKEY = "NP"; + private static final String DATE_TIME_PATTERN = "DTP."; - LocaleResources(LocaleProviderAdapter adapter, Locale locale) { - this.adapter = adapter; + // null singleton cache value + private static final Object NULLOBJECT = new Object(); + + LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) { this.locale = locale; + this.localeData = adapter.getLocaleData(); + type = ((LocaleProviderAdapter)adapter).getAdapterType(); } - public TimeZoneNamesBundle getTimeZoneNames() { - TimeZoneNamesBundle tznames = (TimeZoneNamesBundle) cache.get("TimeZoneNames"); - if (tznames == null) { - tznames = adapter.getLocaleData().getTimeZoneNames(locale); - TimeZoneNamesBundle tznb = (TimeZoneNamesBundle) cache.putIfAbsent("TimeZoneNames", tznames); - if (tznb != null) { - tznames = tznb; + private void removeEmptyReferences() { + Object ref; + while ((ref = referenceQueue.poll()) != null) { + cache.remove(((ResourceReference)ref).getCacheKey()); + } + } + + Object getBreakIteratorInfo(String key) { + Object biInfo; + String cacheKey = BREAK_ITERATOR_INFO + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + if (data == null || ((biInfo = data.get()) == null)) { + biInfo = localeData.getBreakIteratorInfo(locale).getObject(key); + cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue)); + } + + return biInfo; + } + + int getCalendarData(String key) { + Integer caldata; + String cacheKey = CALENDAR_DATA + key; + + removeEmptyReferences(); + + ResourceReference data = cache.get(cacheKey); + if (data == null || ((caldata = (Integer) data.get()) == null)) { + ResourceBundle rb = localeData.getCalendarData(locale); + if (rb.containsKey(key)) { + caldata = Integer.parseInt(rb.getString(key)); + } else { + caldata = 0; + } + + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) caldata, referenceQueue)); + } + + return caldata; + } + + public String getCollationData() { + String key = "Rule"; + String coldata = ""; + + removeEmptyReferences(); + ResourceReference data = cache.get(COLLATION_DATA_CACHEKEY); + if (data == null || ((coldata = (String) data.get()) == null)) { + ResourceBundle rb = localeData.getCollationData(locale); + if (rb.containsKey(key)) { + coldata = rb.getString(key); + } + cache.put(COLLATION_DATA_CACHEKEY, + new ResourceReference(COLLATION_DATA_CACHEKEY, (Object) coldata, referenceQueue)); + } + + return coldata; + } + + public Object[] getDecimalFormatSymbolsData() { + Object[] dfsdata; + + removeEmptyReferences(); + ResourceReference data = cache.get(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY); + if (data == null || ((dfsdata = (Object[]) data.get()) == null)) { + // Note that only dfsdata[0] is prepared here in this method. Other + // elements are provided by the caller, yet they are cached here. + ResourceBundle rb = localeData.getNumberFormatData(locale); + dfsdata = new Object[3]; + + // NumberElements look up. First, try the Unicode extension + String numElemKey; + String numberType = locale.getUnicodeLocaleType("nu"); + if (numberType != null) { + numElemKey = numberType + ".NumberElements"; + if (rb.containsKey(numElemKey)) { + dfsdata[0] = rb.getStringArray(numElemKey); + } + } + + // Next, try DefaultNumberingSystem value + if (dfsdata[0] == null && rb.containsKey("DefaultNumberingSystem")) { + numElemKey = rb.getString("DefaultNumberingSystem") + ".NumberElements"; + if (rb.containsKey(numElemKey)) { + dfsdata[0] = rb.getStringArray(numElemKey); + } + } + + // Last resort. No need to check the availability. + // Just let it throw MissingResourceException when needed. + if (dfsdata[0] == null) { + dfsdata[0] = rb.getStringArray("NumberElements"); + } + + cache.put(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, + new ResourceReference(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, (Object) dfsdata, referenceQueue)); + } + + return dfsdata; + } + + public String getCurrencyName(String key) { + Object currencyName = null; + String cacheKey = CURRENCY_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data != null && ((currencyName = data.get()) != null)) { + if (currencyName.equals(NULLOBJECT)) { + currencyName = null; + } + + return (String) currencyName; + } + + OpenListResourceBundle olrb = localeData.getCurrencyNames(locale); + + if (olrb.containsKey(key)) { + currencyName = olrb.getObject(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, currencyName, referenceQueue)); + } + + return (String) currencyName; + } + + public String getLocaleName(String key) { + Object localeName = null; + String cacheKey = LOCALE_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data != null && ((localeName = data.get()) != null)) { + if (localeName.equals(NULLOBJECT)) { + localeName = null; + } + + return (String) localeName; + } + + OpenListResourceBundle olrb = localeData.getLocaleNames(locale); + + if (olrb.containsKey(key)) { + localeName = olrb.getObject(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, localeName, referenceQueue)); + } + + return (String) localeName; + } + + String[] getTimeZoneNames(String key, int size) { + String[] names = null; + String cacheKey = TIME_ZONE_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((names = (String[]) data.get()) == null)) { + TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); + if (tznb.containsKey(key)) { + names = tznb.getStringArray(key, size); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) names, referenceQueue)); } } - return tznames; + + return names; + } + + @SuppressWarnings("unchecked") + Set getZoneIDs() { + Set zoneIDs = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(ZONE_IDS_CACHEKEY); + if (data == null || ((zoneIDs = (Set) data.get()) == null)) { + TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale); + zoneIDs = rb.keySet(); + cache.put(ZONE_IDS_CACHEKEY, + new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue)); + } + + return zoneIDs; + } + + // zoneStrings are cached separately in TimeZoneNameUtility. + String[][] getZoneStrings() { + TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale); + Set keyset = getZoneIDs(); + // Use a LinkedHashSet to preseve the order + Set value = new LinkedHashSet<>(); + for (String key : keyset) { + value.add(rb.getStringArray(key)); + } + + // Add aliases data for CLDR + if (type == LocaleProviderAdapter.Type.CLDR) { + // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call. + Map aliases = ZoneInfo.getAliasTable(); + for (String alias : aliases.keySet()) { + if (!keyset.contains(alias)) { + String tzid = aliases.get(alias); + if (keyset.contains(tzid)) { + String[] val = rb.getStringArray(tzid); + val[0] = alias; + value.add(val); + } + } + } + } + return value.toArray(new String[0][]); + } + + String[] getCalendarNames(String key) { + String[] names = null; + String cacheKey = CALENDAR_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((names = (String[]) data.get()) == null)) { + ResourceBundle rb = localeData.getDateFormatData(locale); + if (rb.containsKey(key)) { + names = rb.getStringArray(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) names, referenceQueue)); + } + } + + return names; } public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) { @@ -120,32 +372,63 @@ public class LocaleResources { } public String[] getNumberPatterns() { - /* try the cache first */ - String[] numberPatterns = (String[]) cache.get("NumberPatterns"); - if (numberPatterns == null) { /* cache miss */ - ResourceBundle resource = adapter.getLocaleData().getNumberFormatData(locale); + String[] numberPatterns = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(NUMBER_PATTERNS_CACHEKEY); + + if (data == null || ((numberPatterns = (String[]) data.get()) == null)) { + ResourceBundle resource = localeData.getNumberFormatData(locale); numberPatterns = resource.getStringArray("NumberPatterns"); - /* update cache */ - cache.put("NumberPatterns", numberPatterns); + cache.put(NUMBER_PATTERNS_CACHEKEY, + new ResourceReference(NUMBER_PATTERNS_CACHEKEY, (Object) numberPatterns, referenceQueue)); } + return numberPatterns; } + /** + * Returns the FormatData resource bundle of this LocaleResources. + * The FormatData should be used only for accessing extra + * resources required by JSR 310. + */ + public ResourceBundle getFormatData() { + return localeData.getDateFormatData(locale); + } + private String getDateTimePattern(String key, int styleIndex, String calendarType) { String resourceKey = "gregory".equals(calendarType) ? key : calendarType + "." + key; - /* try the cache first */ - String[] patterns = (String[]) cache.get(resourceKey); - if (patterns == null) { /* cache miss */ - ResourceBundle r = adapter.getLocaleData().getDateFormatData(locale); + String cacheKey = DATE_TIME_PATTERN + resourceKey; + String[] patterns = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((patterns = (String[]) data.get()) == null)) { + ResourceBundle r = localeData.getDateFormatData(locale); if (r.containsKey(resourceKey)) { patterns = r.getStringArray(resourceKey); } else { assert !resourceKey.equals(key); patterns = r.getStringArray(key); } - /* update cache */ - cache.putIfAbsent(resourceKey, patterns); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) patterns, referenceQueue)); } + return patterns[styleIndex]; } + + private static class ResourceReference extends SoftReference { + private final String cacheKey; + + ResourceReference(String cacheKey, Object o, ReferenceQueue q) { + super(o, q); + this.cacheKey = cacheKey; + } + + String getCacheKey() { + return cacheKey; + } + } } diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/CallbackInterface.java b/jdk/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java similarity index 65% rename from jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/CallbackInterface.java rename to jdk/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java index 05512a1de68..7046c2e0aed 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/CallbackInterface.java +++ b/jdk/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * 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. + * 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 @@ -21,9 +23,15 @@ * questions. */ -import java.rmi.Remote; -import java.rmi.RemoteException; -public interface CallbackInterface extends Remote { - public void inc() throws RemoteException; - public int getNumDeactivated() throws RemoteException; +package sun.util.locale.provider; + +import sun.util.resources.LocaleData; + +/** + * Accessor for LocaleData + * + * @author Naoto Sato + */ +public interface ResourceBundleBasedAdapter { + public LocaleData getLocaleData(); } diff --git a/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java index 28fd7af5a90..96cb5ef7ba3 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java @@ -25,14 +25,10 @@ package sun.util.locale.provider; -import java.util.LinkedHashSet; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.spi.TimeZoneNameProvider; -import sun.util.calendar.ZoneInfo; -import sun.util.resources.TimeZoneNamesBundle; /** * Concrete implementation of the @@ -123,9 +119,7 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { if (id == null || locale == null) { throw new NullPointerException(); } - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames(); - return rb.containsKey(id) ? rb.getStringArray(id, n) : null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id, n); } /** @@ -136,30 +130,6 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { * @return an array of time zone names arrays */ String[][] getZoneStrings(Locale locale) { - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames(); - Set keyset = rb.keySet(); - // Use a LinkedHashSet to preseve the order - Set value = new LinkedHashSet<>(); - for (String key : keyset) { - value.add(rb.getStringArray(key)); - } - - // Add aliases data for CLDR - if (type == LocaleProviderAdapter.Type.CLDR) { - // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call. - Map aliases = ZoneInfo.getAliasTable(); - for (String alias : aliases.keySet()) { - if (!keyset.contains(alias)) { - String tzid = aliases.get(alias); - if (keyset.contains(tzid)) { - String[] val = rb.getStringArray(tzid); - val[0] = alias; - value.add(val); - } - } - } - } - return value.toArray(new String[0][]); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getZoneStrings(); } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java index a8e09a0d6cf..8c279c1d9e6 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java +++ b/jdk/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java @@ -30,11 +30,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; -import sun.util.resources.OpenListResourceBundle; -import sun.util.resources.TimeZoneNamesBundle; /** * Utility class that deals with the localized time zone names @@ -44,18 +43,20 @@ import sun.util.resources.TimeZoneNamesBundle; */ public final class TimeZoneNameUtility { - /** - * cache to hold time zone resource bundles. Keyed by Locale - */ - private static ConcurrentHashMap> cachedBundles = - new ConcurrentHashMap<>(); - /** * cache to hold time zone localized strings. Keyed by Locale */ private static ConcurrentHashMap> cachedZoneData = new ConcurrentHashMap<>(); + /** + * Cache for managing display names per timezone per locale + * The structure is: + * Map(key=id, value=SoftReference(Map(key=locale, value=displaynames))) + */ + private static final Map>> cachedDisplayNames = + new ConcurrentHashMap<>(); + /** * get time zone localized strings. Enumerate all keys. */ @@ -82,9 +83,9 @@ public final class TimeZoneNameUtility { } // Performs per-ID retrieval. + Set zoneIDs = LocaleProviderAdapter.forJRE().getLocaleResources(locale).getZoneIDs(); List zones = new LinkedList<>(); - OpenListResourceBundle rb = getBundle(locale); - for (String key : rb.keySet()) { + for (String key : zoneIDs) { String[] names = retrieveDisplayNamesImpl(key, locale); if (names != null) { zones.add(names); @@ -137,20 +138,31 @@ public final class TimeZoneNameUtility { private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); - return pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); - } - private static TimeZoneNamesBundle getBundle(Locale locale) { - TimeZoneNamesBundle rb; - SoftReference data = cachedBundles.get(locale); - - if (data == null || ((rb = data.get()) == null)) { - rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(locale); - data = new SoftReference<>(rb); - cachedBundles.put(locale, data); + SoftReference> ref = cachedDisplayNames.get(id); + if (ref != null) { + Map perLocale = ref.get(); + if (perLocale != null) { + String[] names = perLocale.get(locale); + if (names != null) { + return names; + } + names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); + if (names != null) { + perLocale.put(locale, names); + } + return names; + } } - return rb; + String[] names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); + if (names != null) { + Map perLocale = new ConcurrentHashMap<>(); + perLocale.put(locale, names); + ref = new SoftReference<>(perLocale); + cachedDisplayNames.put(id, ref); + } + return names; } /** diff --git a/jdk/src/share/classes/sun/util/resources/LocaleData.java b/jdk/src/share/classes/sun/util/resources/LocaleData.java index 9a7a7c40119..fd9ab9e4ae5 100644 --- a/jdk/src/share/classes/sun/util/resources/LocaleData.java +++ b/jdk/src/share/classes/sun/util/resources/LocaleData.java @@ -98,6 +98,14 @@ public class LocaleData { return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale); } + /** + * Gets a break iterator info resource bundle, using privileges + * to allow accessing a sun.* package. + */ + public ResourceBundle getBreakIteratorInfo(Locale locale) { + return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); + } + /** * Gets a collation data resource bundle, using privileges * to allow accessing a sun.* package. diff --git a/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java b/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java index 950e9ba3a0b..d3fae4bb9c3 100644 --- a/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java +++ b/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java @@ -80,13 +80,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class CurrencyNames_zh_HK extends OpenListResourceBundle { // reparent to zh_TW for traditional Chinese names public CurrencyNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(Locale.TAIWAN); setParent(bundle); } diff --git a/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java b/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java index b796db257c0..16778ffdedc 100644 --- a/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java +++ b/jdk/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java @@ -28,13 +28,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class CurrencyNames_zh_SG extends OpenListResourceBundle { // reparent to zh_CN for simplified Chinese names public CurrencyNames_zh_SG() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(Locale.CHINA); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(Locale.CHINA); setParent(bundle); } diff --git a/jdk/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java b/jdk/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java index fe48363c55f..6609a3fdb96 100644 --- a/jdk/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java +++ b/jdk/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java @@ -28,13 +28,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class LocaleNames_zh_HK extends OpenListResourceBundle { // reparent to zh_TW for traditional Chinese names public LocaleNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getLocaleNames(Locale.TAIWAN); setParent(bundle); } diff --git a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java index 603be5fb272..9694c70b380 100644 --- a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java +++ b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java @@ -41,13 +41,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.TimeZoneNamesBundle; public final class TimeZoneNames_zh_HK extends TimeZoneNamesBundle { // reparent to zh_TW for traditional Chinese names public TimeZoneNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getTimeZoneNames(Locale.TAIWAN); setParent(bundle); } diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h index 7914a1c534a..28885cfb14d 100644 --- a/jdk/src/share/javavm/export/jvm.h +++ b/jdk/src/share/javavm/export/jvm.h @@ -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 @@ -188,9 +188,6 @@ JVM_IsNaN(jdouble d); JNIEXPORT void JNICALL JVM_FillInStackTrace(JNIEnv *env, jobject throwable); -JNIEXPORT void JNICALL -JVM_PrintStackTrace(JNIEnv *env, jobject throwable, jobject printable); - JNIEXPORT jint JNICALL JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); @@ -552,6 +549,13 @@ JNIEXPORT jstring JNICALL JVM_ConstantPoolGetStringAt JNIEXPORT jstring JNICALL JVM_ConstantPoolGetUTF8At (JNIEnv *env, jobject unused, jobject jcpool, jint index); +/* + * Parameter reflection + */ + +JNIEXPORT jobjectArray JNICALL +JVM_GetMethodParameters(JNIEnv *env, jobject method); + /* * java.security.* */ diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp index 08cdc8d3e76..8ad5e556c41 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -352,6 +352,9 @@ const band_init all_band_inits[] = { BAND_INIT(method_Exceptions_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), BAND_INIT(method_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), BAND_INIT(method_metadata_bands, -1, -1), + BAND_INIT(method_MethodParameters_NB, BYTE1_spec, 0), + BAND_INIT(method_MethodParameters_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), + BAND_INIT(method_MethodParameters_flag_I, UNSIGNED5_spec, 0), BAND_INIT(method_attr_bands, -1, -1), BAND_INIT(class_flags_hi, UNSIGNED5_spec, 0), BAND_INIT(class_flags_lo, UNSIGNED5_spec, 0), diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h index b8e322aa1db..c555936d02e 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -212,6 +212,9 @@ enum band_number { e_method_Exceptions_RC, e_method_Signature_RS, e_method_metadata_bands, + e_method_MethodParameters_NB, + e_method_MethodParameters_name_RUN, + e_method_MethodParameters_flag_I, e_method_attr_bands, e_class_flags_hi, @@ -388,6 +391,9 @@ enum band_number { #define method_Exceptions_N all_bands[e_method_Exceptions_N] #define method_Exceptions_RC all_bands[e_method_Exceptions_RC] #define method_Signature_RS all_bands[e_method_Signature_RS] +#define method_MethodParameters_NB all_bands[e_method_MethodParameters_NB] +#define method_MethodParameters_name_RUN all_bands[e_method_MethodParameters_name_RUN] +#define method_MethodParameters_flag_I all_bands[e_method_MethodParameters_flag_I] #define method_attr_bands all_bands[e_method_attr_bands] #define class_flags_hi all_bands[e_class_flags_hi] #define class_flags_lo all_bands[e_class_flags_lo] diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h index dde13b8625b..040d8edd55b 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -59,6 +59,9 @@ #define JAVA7_PACKAGE_MAJOR_VERSION 170 #define JAVA7_PACKAGE_MINOR_VERSION 1 +#define JAVA8_PACKAGE_MAJOR_VERSION 171 +#define JAVA8_PACKAGE_MINOR_VERSION 0 + // magic number for gzip streams (for processing pack200-gzip data) #define GZIP_MAGIC 0x1F8B0800 #define GZIP_MAGIC_MASK 0xFFFFFF00 // last byte is variable "flg" field @@ -120,6 +123,7 @@ enum { METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23, METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24, METHOD_ATTR_AnnotationDefault = 25, + METHOD_ATTR_MethodParameters = 26, CODE_ATTR_StackMapTable = 0, CODE_ATTR_LineNumberTable = 1, CODE_ATTR_LocalVariableTable = 2, @@ -160,6 +164,7 @@ enum { F(METHOD_ATTR_RuntimeVisibleParameterAnnotations,RuntimeVisibleParameterAnnotations) \ F(METHOD_ATTR_RuntimeInvisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations) \ F(METHOD_ATTR_AnnotationDefault,AnnotationDefault) \ + F(METHOD_ATTR_MethodParameters,MethodParameters) \ /*(end)*/ #define CODE_ATTR_DO(F) \ F(CODE_ATTR_StackMapTable,StackMapTable) \ diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp index 1f0d0d2f3f1..6fbc43a18ae 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp @@ -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 @@ -71,7 +71,7 @@ NOT_PRODUCT(static THRTYPE uThread = -1;) unpacker* unpacker::non_mt_current = null; unpacker* unpacker::current() { - assert(uThread == THREAD_SELF); + //assert(uThread == THREAD_SELF); return non_mt_current; } static void set_current_unpacker(unpacker* u) { 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 d7c51978ded..bc91827f66c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -648,13 +648,14 @@ void unpacker::read_file_header() { majver = hdr.getInt(); hdrVals += 2; - int majmin[3][2] = { + int majmin[4][2] = { {JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION}, {JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION}, - {JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION} + {JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION}, + {JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION} }; int majminfound = false; - for (int i = 0 ; i < 3 ; i++) { + for (int i = 0 ; i < 4 ; i++) { if (majver == majmin[i][0] && minver == majmin[i][1]) { majminfound = true; break; @@ -663,11 +664,12 @@ void unpacker::read_file_header() { if (majminfound == null) { char message[200]; sprintf(message, "@" ERROR_FORMAT ": magic/ver = " - "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d\n", + "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d\n", magic, majver, minver, JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION, JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION, - JAVA_PACKAGE_MAGIC, JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION); + JAVA_PACKAGE_MAGIC, JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION, + JAVA_PACKAGE_MAGIC, JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION); abort(message); } CHECK; @@ -2481,6 +2483,13 @@ void unpacker::read_attrs(int attrc, int obj_count) { ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations); ad.readBandData(METHOD_ATTR_AnnotationDefault); CHECK; + + count = ad.predefCount(METHOD_ATTR_MethodParameters); + method_MethodParameters_NB.readData(count); + count = method_MethodParameters_NB.getIntTotal(); + method_MethodParameters_name_RUN.readData(count); + method_MethodParameters_flag_I.readData(count); + CHECK; break; case ATTR_CONTEXT_CODE: @@ -4417,6 +4426,15 @@ int unpacker::write_attrs(int attrc, julong indexBits) { } break; + case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_MethodParameters): + aname = cp.sym[cpool::s_MethodParameters]; + putu1(count = method_MethodParameters_NB.getByte()); + for (j = 0; j < count; j++) { + putref(method_MethodParameters_name_RUN.getRefN()); + putu4(method_MethodParameters_flag_I.getInt()); + } + break; + case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_StackMapTable): aname = cp.sym[cpool::s_StackMapTable]; // (keep this code aligned with its brother in unpacker::read_attrs) diff --git a/jdk/src/share/native/java/lang/reflect/Executable.c b/jdk/src/share/native/java/lang/reflect/Executable.c new file mode 100644 index 00000000000..f6133e8d812 --- /dev/null +++ b/jdk/src/share/native/java/lang/reflect/Executable.c @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include +#include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "java_lang_reflect_Executable.h" + +JNIEXPORT jobject JNICALL +Java_java_lang_reflect_Executable_getParameters0(JNIEnv *env, + jobject method) { + return JVM_GetMethodParameters(env, method); +} diff --git a/jdk/src/share/native/java/util/zip/zip_util.h b/jdk/src/share/native/java/util/zip/zip_util.h index 5771e86320f..5782eaacf40 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.h +++ b/jdk/src/share/native/java/util/zip/zip_util.h @@ -177,8 +177,8 @@ typedef struct jzentry { /* Zip file entry */ */ typedef struct jzcell { unsigned int hash; /* 32 bit hashcode on name */ - jlong cenpos; /* Offset of central directory file header */ unsigned int next; /* hash chain: index into jzfile->entries */ + jlong cenpos; /* Offset of central directory file header */ } jzcell; typedef struct cencache { diff --git a/jdk/src/share/transport/socket/socketTransport.c b/jdk/src/share/transport/socket/socketTransport.c index e3a50d93ecd..666ce2d6d6b 100644 --- a/jdk/src/share/transport/socket/socketTransport.c +++ b/jdk/src/share/transport/socket/socketTransport.c @@ -304,7 +304,7 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, { char buf[20]; - int len = sizeof(sa); + socklen_t len = sizeof(sa); jint portNum; err = dbgsysGetSocketName(serverSocketFD, (struct sockaddr *)&sa, &len); @@ -324,7 +324,8 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, static jdwpTransportError JNICALL socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout) { - int socketLen, err; + socklen_t socketLen; + int err; struct sockaddr_in socket; jlong startTime = (jlong)0; @@ -508,7 +509,7 @@ socketTransport_close(jdwpTransportEnv* env) if (dbgsysSocketClose(fd) < 0) { /* * close failed - it's pointless to restore socketFD here because - * any subsequent close will likely fail aswell. + * any subsequent close will likely fail as well. */ RETURN_IO_ERROR("close failed"); } diff --git a/jdk/src/share/transport/socket/sysSocket.h b/jdk/src/share/transport/socket/sysSocket.h index b40267ab432..f80cc67a1de 100644 --- a/jdk/src/share/transport/socket/sysSocket.h +++ b/jdk/src/share/transport/socket/sysSocket.h @@ -34,28 +34,29 @@ #define DBG_EINPROGRESS -150 #define DBG_ETIMEOUT -200 +#ifdef WIN32 +typedef int socklen_t; +#endif int dbgsysSocketClose(int fd); -int dbgsysConnect(int fd, struct sockaddr *him, int len); -int dbgsysFinishConnect(int fd, long timeout); -int dbgsysAccept(int fd, struct sockaddr *him, int *len); -int dbgsysSendTo(int fd, char *buf, int len, int flags, struct sockaddr *to, - int tolen); -int dbgsysRecvFrom(int fd, char *buf, int nbytes, int flags, - struct sockaddr *from, int *fromlen); +int dbgsysConnect(int fd, struct sockaddr *him, socklen_t len); +int dbgsysFinishConnect(int fd, int timeout); +int dbgsysAccept(int fd, struct sockaddr *him, socklen_t *len); +int dbgsysSendTo(int fd, char *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen); +int dbgsysRecvFrom(int fd, char *buf, size_t nBytes, int flags, struct sockaddr *from, socklen_t *fromlen); int dbgsysListen(int fd, int backlog); -int dbgsysRecv(int fd, char *buf, int nBytes, int flags); -int dbgsysSend(int fd, char *buf, int nBytes, int flags); +int dbgsysRecv(int fd, char *buf, size_t nBytes, int flags); +int dbgsysSend(int fd, char *buf, size_t nBytes, int flags); struct hostent *dbgsysGetHostByName(char *hostname); int dbgsysSocket(int domain, int type, int protocol); -int dbgsysBind(int fd, struct sockaddr *name, int namelen); +int dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen); int dbgsysSetSocketOption(int fd, jint cmd, jboolean on, jvalue value); uint32_t dbgsysInetAddr(const char* cp); uint32_t dbgsysHostToNetworkLong(uint32_t hostlong); unsigned short dbgsysHostToNetworkShort(unsigned short hostshort); uint32_t dbgsysNetworkToHostLong(uint32_t netlong); unsigned short dbgsysNetworkToHostShort(unsigned short netshort); -int dbgsysGetSocketName(int fd, struct sockaddr *him, int *len); +int dbgsysGetSocketName(int fd, struct sockaddr *him, socklen_t *len); int dbgsysConfigureBlocking(int fd, jboolean blocking); int dbgsysPoll(int fd, jboolean rd, jboolean wr, long timeout); int dbgsysGetLastIOError(char *buf, jint size); diff --git a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0d898336e24..693833198b3 100644 --- a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -33,6 +33,7 @@ import java.net.PasswordAuthentication; import java.net.UnknownHostException; import java.net.URL; import java.security.GeneralSecurityException; +import java.util.Base64; import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; @@ -230,7 +231,7 @@ public class NTLMAuthentication extends AuthenticationInfo { private String buildType1Msg () { byte[] msg = client.type1(); - String result = "NTLM " + (new B64Encoder()).encode (msg); + String result = "NTLM " + Base64.getEncoder().encodeToString(msg); return result; } @@ -239,18 +240,12 @@ public class NTLMAuthentication extends AuthenticationInfo { /* First decode the type2 message to get the server nonce */ /* nonce is located at type2[24] for 8 bytes */ - byte[] type2 = (new sun.misc.BASE64Decoder()).decodeBuffer (challenge); + byte[] type2 = Base64.getDecoder().decode(challenge); byte[] nonce = new byte[8]; new java.util.Random().nextBytes(nonce); byte[] msg = client.type3(type2, nonce); - String result = "NTLM " + (new B64Encoder()).encode (msg); + String result = "NTLM " + Base64.getEncoder().encodeToString(msg); return result; } } -class B64Encoder extends sun.misc.BASE64Encoder { - /* to force it to to the entire encoding in one line */ - protected int bytesPerLine () { - return 1024; - } -} diff --git a/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java index 54023bf8265..74c804d94d9 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java @@ -52,10 +52,10 @@ class SolarisAclFileAttributeView /** * typedef struct ace { * uid_t a_who; - * uitn32_t a_access_mark; + * uint32_t a_access_mask; * uint16_t a_flags; * uint16_t a_type; - * } act_t; + * } ace_t; */ private static final short SIZEOF_ACE_T = 12; private static final short OFFSETOF_UID = 0; @@ -209,21 +209,16 @@ class SolarisAclFileAttributeView // map uid and flags to UserPrincipal UnixUserPrincipals.User who = null; - if (uid == -1) { - if ((flags & ACE_OWNER) > 0) - who = UnixUserPrincipals.SPECIAL_OWNER; - if ((flags & ACE_GROUP) > 0) - who = UnixUserPrincipals.SPECIAL_GROUP; - if ((flags & ACE_EVERYONE) > 0) - who = UnixUserPrincipals.SPECIAL_EVERYONE; - if (who == null) - throw new AssertionError("ACE who not handled"); + if ((flags & ACE_OWNER) > 0) { + who = UnixUserPrincipals.SPECIAL_OWNER; + } else if ((flags & ACE_GROUP) > 0) { + who = UnixUserPrincipals.SPECIAL_GROUP; + } else if ((flags & ACE_EVERYONE) > 0) { + who = UnixUserPrincipals.SPECIAL_EVERYONE; + } else if ((flags & ACE_IDENTIFIER_GROUP) > 0) { + who = UnixUserPrincipals.fromGid(uid); } else { - // can be gid - if ((flags & ACE_IDENTIFIER_GROUP) > 0) - who = UnixUserPrincipals.fromGid(uid); - else - who = UnixUserPrincipals.fromUid(uid); + who = UnixUserPrincipals.fromUid(uid); } AclEntryType aceType = null; diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java index a6b79953add..b61b5d6e4a0 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java @@ -45,9 +45,12 @@ class UnixFileAttributes private int st_uid; private int st_gid; private long st_size; - private long st_atime; - private long st_mtime; - private long st_ctime; + private long st_atime_sec; + private long st_atime_nsec; + private long st_mtime_sec; + private long st_mtime_nsec; + private long st_ctime_sec; + private long st_ctime_nsec; // created lazily private volatile UserPrincipal owner; @@ -101,8 +104,20 @@ class UnixFileAttributes int uid() { return st_uid; } int gid() { return st_gid; } + private static FileTime toFileTime(long sec, long nsec) { + if (nsec == 0) { + return FileTime.from(sec, TimeUnit.SECONDS); + } else { + // truncate to microseconds to avoid overflow with timestamps + // way out into the future. We can re-visit this if FileTime + // is updated to define a from(secs,nsecs) method. + long micro = sec*1000000L + nsec/1000L; + return FileTime.from(micro, TimeUnit.MICROSECONDS); + } + } + FileTime ctime() { - return FileTime.from(st_ctime, TimeUnit.SECONDS); + return toFileTime(st_ctime_sec, st_ctime_nsec); } boolean isDevice() { @@ -114,12 +129,12 @@ class UnixFileAttributes @Override public FileTime lastModifiedTime() { - return FileTime.from(st_mtime, TimeUnit.SECONDS); + return toFileTime(st_mtime_sec, st_mtime_nsec); } @Override public FileTime lastAccessTime() { - return FileTime.from(st_atime, TimeUnit.SECONDS); + return toFileTime(st_atime_sec, st_atime_nsec); } @Override diff --git a/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c index 45d1191c43a..eb4698183df 100644 --- a/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c +++ b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c @@ -90,9 +90,12 @@ static jfieldID attrs_st_nlink; static jfieldID attrs_st_uid; static jfieldID attrs_st_gid; static jfieldID attrs_st_size; -static jfieldID attrs_st_atime; -static jfieldID attrs_st_mtime; -static jfieldID attrs_st_ctime; +static jfieldID attrs_st_atime_sec; +static jfieldID attrs_st_atime_nsec; +static jfieldID attrs_st_mtime_sec; +static jfieldID attrs_st_mtime_nsec; +static jfieldID attrs_st_ctime_sec; +static jfieldID attrs_st_ctime_nsec; static jfieldID attrs_f_frsize; static jfieldID attrs_f_blocks; @@ -183,9 +186,12 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I"); attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I"); attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J"); - attrs_st_atime = (*env)->GetFieldID(env, clazz, "st_atime", "J"); - attrs_st_mtime = (*env)->GetFieldID(env, clazz, "st_mtime", "J"); - attrs_st_ctime = (*env)->GetFieldID(env, clazz, "st_ctime", "J"); + attrs_st_atime_sec = (*env)->GetFieldID(env, clazz, "st_atime_sec", "J"); + attrs_st_atime_nsec = (*env)->GetFieldID(env, clazz, "st_atime_nsec", "J"); + attrs_st_mtime_sec = (*env)->GetFieldID(env, clazz, "st_mtime_sec", "J"); + attrs_st_mtime_nsec = (*env)->GetFieldID(env, clazz, "st_mtime_nsec", "J"); + attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J"); + attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J"); clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); if (clazz == NULL) { @@ -395,9 +401,15 @@ static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); - (*env)->SetLongField(env, attrs, attrs_st_atime, (jlong)buf->st_atime); - (*env)->SetLongField(env, attrs, attrs_st_mtime, (jlong)buf->st_mtime); - (*env)->SetLongField(env, attrs, attrs_st_ctime, (jlong)buf->st_ctime); + (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime); + (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); + (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); + +#if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__) + (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); + (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); + (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec); +#endif } JNIEXPORT void JNICALL diff --git a/jdk/src/solaris/transport/socket/socket_md.c b/jdk/src/solaris/transport/socket/socket_md.c index 74e8d846c7b..715b7ac066a 100644 --- a/jdk/src/solaris/transport/socket/socket_md.c +++ b/jdk/src/solaris/transport/socket/socket_md.c @@ -49,7 +49,7 @@ dbgsysListen(int fd, int backlog) { } int -dbgsysConnect(int fd, struct sockaddr *name, int namelen) { +dbgsysConnect(int fd, struct sockaddr *name, socklen_t namelen) { int rv = connect(fd, name, namelen); if (rv < 0 && (errno == EINPROGRESS || errno == EINTR)) { return DBG_EINPROGRESS; @@ -59,7 +59,7 @@ dbgsysConnect(int fd, struct sockaddr *name, int namelen) { } int -dbgsysFinishConnect(int fd, long timeout) { +dbgsysFinishConnect(int fd, int timeout) { int rv = dbgsysPoll(fd, 0, 1, timeout); if (rv == 0) { return DBG_ETIMEOUT; @@ -71,7 +71,7 @@ dbgsysFinishConnect(int fd, long timeout) { } int -dbgsysAccept(int fd, struct sockaddr *name, int *namelen) { +dbgsysAccept(int fd, struct sockaddr *name, socklen_t *namelen) { int rv; for (;;) { rv = accept(fd, name, namelen); @@ -85,8 +85,8 @@ dbgsysAccept(int fd, struct sockaddr *name, int *namelen) { } int -dbgsysRecvFrom(int fd, char *buf, int nBytes, - int flags, struct sockaddr *from, int *fromlen) { +dbgsysRecvFrom(int fd, char *buf, size_t nBytes, + int flags, struct sockaddr *from, socklen_t *fromlen) { int rv; do { rv = recvfrom(fd, buf, nBytes, flags, from, fromlen); @@ -96,8 +96,8 @@ dbgsysRecvFrom(int fd, char *buf, int nBytes, } int -dbgsysSendTo(int fd, char *buf, int len, - int flags, struct sockaddr *to, int tolen) { +dbgsysSendTo(int fd, char *buf, size_t len, + int flags, struct sockaddr *to, socklen_t tolen) { int rv; do { rv = sendto(fd, buf, len, flags, to, tolen); @@ -107,7 +107,7 @@ dbgsysSendTo(int fd, char *buf, int len, } int -dbgsysRecv(int fd, char *buf, int nBytes, int flags) { +dbgsysRecv(int fd, char *buf, size_t nBytes, int flags) { int rv; do { rv = recv(fd, buf, nBytes, flags); @@ -117,7 +117,7 @@ dbgsysRecv(int fd, char *buf, int nBytes, int flags) { } int -dbgsysSend(int fd, char *buf, int nBytes, int flags) { +dbgsysSend(int fd, char *buf, size_t nBytes, int flags) { int rv; do { rv = send(fd, buf, nBytes, flags); @@ -151,7 +151,7 @@ int dbgsysSocketClose(int fd) { } int -dbgsysBind(int fd, struct sockaddr *name, int namelen) { +dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) { return bind(fd, name, namelen); } @@ -171,7 +171,7 @@ dbgsysNetworkToHostShort(unsigned short netshort) { } int -dbgsysGetSocketName(int fd, struct sockaddr *name, int *namelen) { +dbgsysGetSocketName(int fd, struct sockaddr *name, socklen_t *namelen) { return getsockname(fd, name, namelen); } diff --git a/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java index 5e6cbb02f31..a3ac941a7a2 100644 --- a/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java +++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java @@ -26,8 +26,7 @@ package sun.net.www.protocol.http.ntlm; import java.io.IOException; -import sun.misc.BASE64Encoder; -import sun.misc.BASE64Decoder; +import java.util.Base64; /* * Hooks into Windows implementation of NTLM. @@ -77,11 +76,11 @@ public class NTLMAuthSequence { assert !status.sequenceComplete; if (token != null) - input = (new BASE64Decoder()).decodeBuffer(token); + input = Base64.getDecoder().decode(token); byte[] b = getNextToken (crdHandle, input, status); if (b == null) throw new IOException ("Internal authentication error"); - return (new B64Encoder()).encode (b); + return Base64.getEncoder().encodeToString(b); } public boolean isComplete() { @@ -95,8 +94,3 @@ public class NTLMAuthSequence { private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned); } -class B64Encoder extends BASE64Encoder { - protected int bytesPerLine () { - return 1024; - } -} diff --git a/jdk/src/windows/native/java/lang/java_props_md.c b/jdk/src/windows/native/java/lang/java_props_md.c index 5d1111efbee..3374bd44225 100644 --- a/jdk/src/windows/native/java/lang/java_props_md.c +++ b/jdk/src/windows/native/java/lang/java_props_md.c @@ -23,6 +23,11 @@ * questions. */ +/* Access APIs for Windows Vista and above */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif + #include #include #include @@ -49,8 +54,6 @@ typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); static void SetupI18nProps(LCID lcid, char** language, char** script, char** country, char** variant, char** encoding); -#define SHELL_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" - #define PROPSIZE 9 // eight-letter + null terminator #define SNAMESIZE 86 // max number of chars for LOCALE_SNAME is 85 @@ -173,76 +176,54 @@ getJavaIDFromLangID(LANGID langID) return ret; } -/* - * Code to figure out the user's home directory using the registry -*/ -static WCHAR* -getHomeFromRegistry() -{ - HKEY key; - int rc; - DWORD type; - WCHAR *p; - WCHAR path[MAX_PATH+1]; - int size = MAX_PATH+1; - - rc = RegOpenKeyEx(HKEY_CURRENT_USER, SHELL_KEY, 0, KEY_READ, &key); - if (rc != ERROR_SUCCESS) { - // Shell folder doesn't exist??!! - return NULL; - } - - path[0] = 0; - rc = RegQueryValueExW(key, L"Desktop", 0, &type, (LPBYTE)path, &size); - if (rc != ERROR_SUCCESS || type != REG_SZ) { - return NULL; - } - RegCloseKey(key); - /* Get the parent of Desktop directory */ - p = wcsrchr(path, L'\\'); - if (p == NULL) { - return NULL; - } - *p = L'\0'; - return _wcsdup(path); -} - /* * Code to figure out the user's home directory using shell32.dll */ WCHAR* getHomeFromShell32() { - HRESULT rc; - LPITEMIDLIST item_list = 0; - WCHAR *p; - WCHAR path[MAX_PATH+1]; - int size = MAX_PATH+1; - - rc = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &item_list); - if (!SUCCEEDED(rc)) { - // we can't find the shell folder. - return NULL; - } - - path[0] = 0; - SHGetPathFromIDListW(item_list, (LPWSTR)path); - - /* Get the parent of Desktop directory */ - p = wcsrchr(path, L'\\'); - if (p) { - *p = 0; - } - /* - * We've been successful. Note that we don't free the memory allocated - * by ShGetSpecialFolderLocation. We only ever come through here once, - * and only if the registry lookup failed, so it's just not worth it. - * - * We also don't unload the SHELL32 DLL. We've paid the hit for loading - * it and we may need it again later. + * Note that we don't free the memory allocated + * by getHomeFromShell32. */ - return _wcsdup(path); + static WCHAR *u_path = NULL; + if (u_path == NULL) { + HRESULT hr; + + /* + * SHELL32 DLL is delay load DLL and we can use the trick with + * __try/__except block. + */ + __try { + /* + * For Windows Vista and later (or patched MS OS) we need to use + * [SHGetKnownFolderPath] call to avoid MAX_PATH length limitation. + * Shell32.dll (version 6.0.6000 or later) + */ + hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &u_path); + } __except(EXCEPTION_EXECUTE_HANDLER) { + /* Exception: no [SHGetKnownFolderPath] entry */ + hr = E_FAIL; + } + + if (FAILED(hr)) { + WCHAR path[MAX_PATH+1]; + + /* fallback solution for WinXP and Windows 2000 */ + hr = SHGetFolderPathW(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path); + if (FAILED(hr)) { + /* we can't find the shell folder. */ + u_path = NULL; + } else { + /* Just to be sure about the path length until Windows Vista approach. + * [S_FALSE] could not be returned due to [CSIDL_FLAG_DONT_VERIFY] flag and UNICODE version. + */ + path[MAX_PATH] = 0; + u_path = _wcsdup(path); + } + } + } + return u_path; } static boolean @@ -336,7 +317,7 @@ GetJavaProperties(JNIEnv* env) OSVERSIONINFOEX ver; - if (sprops.user_dir) { + if (sprops.line_separator) { return &sprops; } @@ -538,15 +519,7 @@ GetJavaProperties(JNIEnv* env) } /* - * Home directory/ - * - * We first look under a standard registry key. If that fails we - * fall back on using a SHELL32.DLL API. If that fails we use a - * default value. - * - * Note: To save space we want to avoid loading SHELL32.DLL - * unless really necessary. However if we do load it, we leave it - * in memory, as it may be needed again later. + * Home directory * * The normal result is that for a given user name XXX: * On multi-user NT, user.home gets set to c:\winnt\profiles\XXX. @@ -554,13 +527,11 @@ GetJavaProperties(JNIEnv* env) * On single-user Win95, user.home gets set to c:\windows. */ { - WCHAR *homep = getHomeFromRegistry(); + WCHAR *homep = getHomeFromShell32(); if (homep == NULL) { - homep = getHomeFromShell32(); - if (homep == NULL) - homep = L"C:\\"; + homep = L"C:\\"; } - sprops.user_home = _wcsdup(homep); + sprops.user_home = homep; } /* diff --git a/jdk/src/windows/transport/socket/socket_md.c b/jdk/src/windows/transport/socket/socket_md.c index 5b025cf2f4e..8ac98c96aae 100644 --- a/jdk/src/windows/transport/socket/socket_md.c +++ b/jdk/src/windows/transport/socket/socket_md.c @@ -125,7 +125,7 @@ dbgsysListen(int fd, int backlog) { } int -dbgsysConnect(int fd, struct sockaddr *name, int namelen) { +dbgsysConnect(int fd, struct sockaddr *name, socklen_t namelen) { int rv = connect(fd, name, namelen); if (rv == SOCKET_ERROR) { if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) { @@ -135,7 +135,7 @@ dbgsysConnect(int fd, struct sockaddr *name, int namelen) { return rv; } -int dbgsysFinishConnect(int fd, long timeout) { +int dbgsysFinishConnect(int fd, int timeout) { int rv; struct timeval t; fd_set wr, ex; @@ -171,30 +171,30 @@ int dbgsysFinishConnect(int fd, long timeout) { int -dbgsysAccept(int fd, struct sockaddr *name, int *namelen) { +dbgsysAccept(int fd, struct sockaddr *name, socklen_t *namelen) { return (int)accept(fd, name, namelen); } int -dbgsysRecvFrom(int fd, char *buf, int nBytes, - int flags, struct sockaddr *from, int *fromlen) { - return recvfrom(fd, buf, nBytes, flags, from, fromlen); +dbgsysRecvFrom(int fd, char *buf, size_t nBytes, + int flags, struct sockaddr *from, socklen_t *fromlen) { + return recvfrom(fd, buf, (int)nBytes, flags, from, fromlen); } int -dbgsysSendTo(int fd, char *buf, int len, - int flags, struct sockaddr *to, int tolen) { - return sendto(fd, buf, len, flags, to, tolen); +dbgsysSendTo(int fd, char *buf, size_t len, + int flags, struct sockaddr *to, socklen_t tolen) { + return sendto(fd, buf, (int)len, flags, to, tolen); } int -dbgsysRecv(int fd, char *buf, int nBytes, int flags) { - return recv(fd, buf, nBytes, flags); +dbgsysRecv(int fd, char *buf, size_t nBytes, int flags) { + return recv(fd, buf, (int) nBytes, flags); } int -dbgsysSend(int fd, char *buf, int nBytes, int flags) { - return send(fd, buf, nBytes, flags); +dbgsysSend(int fd, char *buf, size_t nBytes, int flags) { + return send(fd, buf, (int)nBytes, flags); } struct hostent * @@ -232,7 +232,7 @@ dbgsysSocketClose(int fd) { /* Additions to original follow */ int -dbgsysBind(int fd, struct sockaddr *name, int namelen) { +dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) { return bind(fd, name, namelen); } @@ -253,7 +253,7 @@ dbgsysNetworkToHostShort(unsigned short netshort) { } int -dbgsysGetSocketName(int fd, struct sockaddr *name, int *namelen) { +dbgsysGetSocketName(int fd, struct sockaddr *name, socklen_t *namelen) { return getsockname(fd, name, namelen); } @@ -426,7 +426,7 @@ dbgsysTlsGet(int index) { } #define FT2INT64(ft) \ - ((long)(ft).dwHighDateTime << 32 | (long)(ft).dwLowDateTime) + ((INT64)(ft).dwHighDateTime << 32 | (INT64)(ft).dwLowDateTime) long dbgsysCurrentTimeMillis() { diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 871cc54dc2c..408aaaeed25 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -498,6 +498,11 @@ JDK_DEFAULT_TARGETS += jdk_math jdk_math: $(call TestDirs, java/math) $(call RunAgentvmBatch) +# Stable agentvm testruns (TestNG) +JDK_DEFAULT_TARGETS += jdk_time +jdk_time: $(call TestDirs, java/time) + $(call RunOthervmBatch) + # Stable agentvm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_other JDK_DEFAULT_TARGETS += jdk_other diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 3aa7cfff170..5e181ac7e03 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -288,6 +288,9 @@ sun/security/mscapi/ShortRSAKey1024.sh windows-all # 8000897, vm crash sun/security/provider/DSA/TestAlgParameterGenerator.java generic-all +# 7144048, performance issue +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineDeadlock.java generic-all + ############################################################################ # jdk_sound @@ -318,12 +321,12 @@ sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all tools/pack200/CommandLineTests.java generic-all tools/pack200/Pack200Test.java generic-all +# 8001163 +tools/pack200/AttributeTests.java generic-all + # 7150569 tools/launcher/UnicodeTest.java macosx-all -# 8005252 -tools/pack200/AttributeTests.java generic-all - ############################################################################ # jdk_jdi diff --git a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh index fe11904a471..9d750c5627f 100644 --- a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh +++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh @@ -32,15 +32,15 @@ # @build DumpHeap # @run shell DumpHeap.sh -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else +if [ "${TESTJAVA}" = "" ] ; then echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + failed=0 # we use the pid of this shell process to name the heap dump output file. @@ -50,7 +50,7 @@ ${TESTJAVA}/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES \ DumpHeap ${DUMPFILE} || exit 2 # check that heap dump is parsable -${TESTJAVA}/bin/jhat -parseonly true ${DUMPFILE} +${COMPILEJAVA}/bin/jhat ${TESTTOOLVMOPTS} -parseonly true ${DUMPFILE} if [ $? != 0 ]; then failed=1; fi # dump file is large so remove it diff --git a/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetMaxFileDescriptorCount.sh b/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetMaxFileDescriptorCount.sh index 47110c0e752..401a40008bf 100644 --- a/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetMaxFileDescriptorCount.sh +++ b/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetMaxFileDescriptorCount.sh @@ -30,19 +30,19 @@ # @run shell GetMaxFileDescriptorCount.sh # -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else +if [ "${TESTJAVA}" = "" ] ; then echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi runOne() { echo "runOne $@" - $TESTJAVA/bin/javac -d $TESTCLASSES $TESTSRC/$@.java || exit 2 + $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d $TESTCLASSES \ + $TESTSRC/$@.java || exit 2 $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 3 } diff --git a/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetOpenFileDescriptorCount.sh b/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetOpenFileDescriptorCount.sh index bc3ef465fc3..28ea936733d 100644 --- a/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetOpenFileDescriptorCount.sh +++ b/jdk/test/com/sun/management/UnixOperatingSystemMXBean/GetOpenFileDescriptorCount.sh @@ -30,19 +30,18 @@ # @run shell GetOpenFileDescriptorCount.sh # -#Set appropriate jdk - -if [ ! -z "${TESTJAVA}" ] ; then - jdk="$TESTJAVA" -else +if [ "${TESTJAVA}" = "" ] ; then echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test." exit 1 fi - +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi runOne() { echo "runOne $@" - $TESTJAVA/bin/javac -d $TESTCLASSES $TESTSRC/$@.java || exit 2 + $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d $TESTCLASSES \ + $TESTSRC/$@.java || exit 2 $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 3 } diff --git a/jdk/test/java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java b/jdk/test/java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java new file mode 100644 index 00000000000..d42137af303 --- /dev/null +++ b/jdk/test/java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java @@ -0,0 +1,156 @@ +/* + * 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.AWTException; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.image.BufferedImage; + +import sun.awt.SunToolkit; + +/** + * @test + * @bug 8003173 7019055 + * @summary Full-screen windows should have the proper insets. + * @author Sergey Bylokhov + */ +public final class FullScreenInsets { + + private static boolean passed = true; + + public static void main(final String[] args) { + final GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + final GraphicsDevice[] devices = ge.getScreenDevices(); + + final Window wGreen = new Frame(); + wGreen.setBackground(Color.GREEN); + wGreen.setSize(300, 300); + wGreen.setVisible(true); + sleep(); + final Insets iGreen = wGreen.getInsets(); + final Dimension sGreen = wGreen.getSize(); + + final Window wRed = new Frame(); + wRed.setBackground(Color.RED); + wRed.setSize(300, 300); + wRed.setVisible(true); + sleep(); + final Insets iRed = wGreen.getInsets(); + final Dimension sRed = wGreen.getSize(); + + for (final GraphicsDevice device : devices) { + if (!device.isFullScreenSupported()) { + continue; + } + device.setFullScreenWindow(wGreen); + sleep(); + testWindowBounds(device.getDisplayMode(), wGreen); + testColor(wGreen, Color.GREEN); + + device.setFullScreenWindow(wRed); + sleep(); + testWindowBounds(device.getDisplayMode(), wRed); + testColor(wRed, Color.RED); + + device.setFullScreenWindow(null); + sleep(); + testInsets(wGreen.getInsets(), iGreen); + testInsets(wRed.getInsets(), iRed); + testSize(wGreen.getSize(), sGreen); + testSize(wRed.getSize(), sRed); + } + wGreen.dispose(); + wRed.dispose(); + if (!passed) { + throw new RuntimeException("Test failed"); + } + } + + private static void testSize(final Dimension actual, final Dimension exp) { + if (!exp.equals(actual)) { + System.err.println(" Wrong window size:" + + " Expected: " + exp + " Actual: " + actual); + passed = false; + } + } + + private static void testInsets(final Insets actual, final Insets exp) { + if (!actual.equals(exp)) { + System.err.println(" Wrong window insets:" + + " Expected: " + exp + " Actual: " + actual); + passed = false; + } + } + + private static void testWindowBounds(final DisplayMode dm, final Window w) { + if (w.getWidth() != dm.getWidth() || w.getHeight() != dm.getHeight()) { + System.err.println(" Wrong window bounds:" + + " Expected: width = " + dm.getWidth() + + ", height = " + dm.getHeight() + " Actual: " + + w.getSize()); + passed = false; + } + } + + private static void testColor(final Window w, final Color color) { + final Robot r; + try { + r = new Robot(w.getGraphicsConfiguration().getDevice()); + } catch (AWTException e) { + e.printStackTrace(); + passed = false; + return; + } + final BufferedImage bi = r.createScreenCapture(w.getBounds()); + for (int y = 0; y < bi.getHeight(); y++) { + for (int x = 0; x < bi.getWidth(); x++) { + if (bi.getRGB(x, y) != color.getRGB()) { + System.err.println( + "Incorrect pixel at " + x + "x" + y + " : " + + Integer.toHexString(bi.getRGB(x, y)) + + " ,expected : " + Integer.toHexString( + color.getRGB())); + passed = false; + return; + } + } + } + } + + private static void sleep() { + ((SunToolkit) Toolkit.getDefaultToolkit()).realSync(); + try { + Thread.sleep(2000); + } catch (InterruptedException ignored) { + } + } +} diff --git a/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java b/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java index f01b8856f0f..d95441ba1bc 100644 --- a/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java +++ b/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java @@ -36,6 +36,7 @@ import java.applet.Applet; import java.util.concurrent.atomic.AtomicBoolean; import java.lang.reflect.InvocationTargetException; import test.java.awt.regtesthelpers.Util; +import sun.awt.OSInfo; public class SubMenuShowTest extends Applet { Robot robot; @@ -86,6 +87,11 @@ public class SubMenuShowTest extends Applet { frame.setVisible(true); Util.waitForIdle(robot); + boolean isMacOSX = (OSInfo.getOSType() == OSInfo.OSType.MACOSX); + if (isMacOSX) { + robot.keyPress(KeyEvent.VK_CONTROL); + robot.delay(20); + } robot.keyPress(KeyEvent.VK_ALT); robot.delay(20); robot.keyPress(KeyEvent.VK_F); @@ -93,6 +99,10 @@ public class SubMenuShowTest extends Applet { robot.keyRelease(KeyEvent.VK_F); robot.delay(20); robot.keyRelease(KeyEvent.VK_ALT); + if (isMacOSX) { + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.delay(20); + } Util.waitForIdle(robot); robot.keyPress(KeyEvent.VK_M); diff --git a/jdk/test/java/beans/Introspector/TestTypeResolver.java b/jdk/test/java/beans/Introspector/TestTypeResolver.java index 6704d8f7e16..e6915192776 100644 --- a/jdk/test/java/beans/Introspector/TestTypeResolver.java +++ b/jdk/test/java/beans/Introspector/TestTypeResolver.java @@ -180,10 +180,22 @@ public class TestTypeResolver { return null; // not used } + public T[] getAnnotations(Class annotationClass) { + return null; // not used + } + public Annotation[] getAnnotations() { return null; // not used } + public T getDeclaredAnnotation(Class annotationClass) { + return null; // not used + } + + public T[] getDeclaredAnnotations(Class annotationClass) { + return null; // not used + } + public Annotation[] getDeclaredAnnotations() { return null; // not used } diff --git a/jdk/test/java/io/FileOutputStream/FileOpen.sh b/jdk/test/java/io/FileOutputStream/FileOpen.sh index d79c262d441..83dfb2773e4 100644 --- a/jdk/test/java/io/FileOutputStream/FileOpen.sh +++ b/jdk/test/java/io/FileOutputStream/FileOpen.sh @@ -46,8 +46,10 @@ case "$OS" in echo "Could not find the directory-" ${TMP} "- passing test" exit 0; fi - ${TESTJAVA}/bin/javac -d . ${TESTSRC}\\FileOpenPos.java - ${TESTJAVA}/bin/javac -d . ${TESTSRC}\\FileOpenNeg.java + ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}\\FileOpenPos.java + ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}\\FileOpenNeg.java echo "Opening Writable Normal File.." ${TESTJAVA}/bin/java ${TESTVMOPTS} FileOpenPos ${hfile} diff --git a/jdk/test/java/io/Serializable/class/run.sh b/jdk/test/java/io/Serializable/class/run.sh index 26ad083908b..9d82501d01b 100644 --- a/jdk/test/java/io/Serializable/class/run.sh +++ b/jdk/test/java/io/Serializable/class/run.sh @@ -34,17 +34,21 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then TESTSRC="." fi -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Test.java echo Write NonSerial1, Read NonSerial1 rm -f A.java cp ${TESTSRC}/NonSerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -d echo @@ -52,77 +56,77 @@ echo echo Write NonSerial1, Read NonSerial2 rm -f A.java cp ${TESTSRC}/NonSerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/NonSerialA_2.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -d echo echo Write NonSerial1, Read Serial1 rm -f A.java cp ${TESTSRC}/NonSerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -d echo echo Write Serial1, Read NonSerial1 rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/NonSerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -doe echo echo Write Serial1, Read Serial2 rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/SerialA_2.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -d echo echo Write Serial2, Read Serial1 rm -f A.java cp ${TESTSRC}/SerialA_2.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -d echo echo Write Serial1, Read Serial3 rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/SerialA_3.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -de echo echo Write Serial3, Read Serial1 rm -f A.java cp ${TESTSRC}/SerialA_3.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -s A rm -f A.java cp ${TESTSRC}/SerialA_1.java A.java -${TESTJAVA}/bin/javac A.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test -de echo diff --git a/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh b/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh index afa751a8474..deda2826115 100644 --- a/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh +++ b/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh @@ -36,6 +36,10 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + OS=`uname -s` # Need to determine the classpath separator and filepath separator based on the @@ -51,7 +55,7 @@ Windows* | CYGWIN* ) esac JAVA=${TESTJAVA}/bin/java -JAVAC=${TESTJAVA}/bin/javac +JAVAC=${COMPILEJAVA}/bin/javac MKDIR=mkdir RDEL="rm -r" @@ -78,11 +82,14 @@ mkdir ${TESTCLASSES}/nclasses # Build sources set -e -${JAVAC} -d ${TESTCLASSES}/share ${TESTSRC}/extension/ExtendedObjectInputStream.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}/share \ + ${TESTSRC}/extension/ExtendedObjectInputStream.java CLASSPATH=${TESTCLASSES}/share; export CLASSPATH; -${JAVAC} -d ${TESTCLASSES}/oclasses ${TESTSRC}/test/SerialDriver.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}/oclasses \ + ${TESTSRC}/test/SerialDriver.java CLASSPATH=${TESTCLASSES}/share; export CLASSPATH; -${JAVAC} -d ${TESTCLASSES}/nclasses ${TESTSRC}/install/SerialDriver.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}/nclasses \ + ${TESTSRC}/install/SerialDriver.java # Run Case 1. Map test.SerialDriver within stream to install.SerialDriver. CLASSPATH="${TESTCLASSES}/oclasses${PS}${TESTCLASSES}/share"; export CLASSPATH; diff --git a/jdk/test/java/io/Serializable/maskSyntheticModifier/run.sh b/jdk/test/java/io/Serializable/maskSyntheticModifier/run.sh index 075e0dfafb8..fdf903fd5c4 100644 --- a/jdk/test/java/io/Serializable/maskSyntheticModifier/run.sh +++ b/jdk/test/java/io/Serializable/maskSyntheticModifier/run.sh @@ -29,17 +29,21 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex cp ${TESTSRC}/Foo.class . -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Test.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test rm -f *.class diff --git a/jdk/test/java/io/Serializable/packageAccess/run.sh b/jdk/test/java/io/Serializable/packageAccess/run.sh index 3a7f0c148f7..7c946674fd1 100644 --- a/jdk/test/java/io/Serializable/packageAccess/run.sh +++ b/jdk/test/java/io/Serializable/packageAccess/run.sh @@ -29,20 +29,25 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex -${TESTJAVA}/bin/javac -d . ${TESTSRC}/A.java ${TESTSRC}/B.java \ - ${TESTSRC}/C.java ${TESTSRC}/D.java ${TESTSRC}/Test.java -${TESTJAVA}/bin/jar cf foo.jar B.class D.class +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}/A.java ${TESTSRC}/B.java ${TESTSRC}/C.java ${TESTSRC}/D.java \ + ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/jar ${TESTTOOLVMOPTS} cf foo.jar B.class D.class rm -f B.class D.class ${TESTJAVA}/bin/java ${TESTVMOPTS} Test diff --git a/jdk/test/java/io/Serializable/resolveClass/consTest/run.sh b/jdk/test/java/io/Serializable/resolveClass/consTest/run.sh index 62cc8ff759a..22e1fb7800b 100644 --- a/jdk/test/java/io/Serializable/resolveClass/consTest/run.sh +++ b/jdk/test/java/io/Serializable/resolveClass/consTest/run.sh @@ -28,21 +28,26 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex rm -f *.class *.jar -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Boot.java -${TESTJAVA}/bin/jar cf boot.jar *.class +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Boot.java +${COMPILEJAVA}/bin/jar ${TESTTOOLVMOPTS} cf boot.jar *.class rm -f *.class -${TESTJAVA}/bin/javac -classpath boot.jar -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath boot.jar -d . \ + ${TESTSRC}/Test.java ${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:boot.jar Test rm -f *.class *.jar diff --git a/jdk/test/java/io/Serializable/resolveClass/deserializeButton/run.sh b/jdk/test/java/io/Serializable/resolveClass/deserializeButton/run.sh index 48208aec4b8..d9cdc3e5078 100644 --- a/jdk/test/java/io/Serializable/resolveClass/deserializeButton/run.sh +++ b/jdk/test/java/io/Serializable/resolveClass/deserializeButton/run.sh @@ -30,21 +30,25 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex rm -f *.class *.jar -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Foo.java -${TESTJAVA}/bin/jar cf cb.jar *.class +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Foo.java +${COMPILEJAVA}/bin/jar ${TESTTOOLVMOPTS} cf cb.jar *.class rm -f *.class -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Test.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test rm -f *.class *.jar diff --git a/jdk/test/java/io/Serializable/superclassDataLoss/run.sh b/jdk/test/java/io/Serializable/superclassDataLoss/run.sh index 44473748e3d..52b6c87d41c 100644 --- a/jdk/test/java/io/Serializable/superclassDataLoss/run.sh +++ b/jdk/test/java/io/Serializable/superclassDataLoss/run.sh @@ -29,22 +29,28 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex -${TESTJAVA}/bin/javac -d . ${TESTSRC}/A.java ${TESTSRC}/B.java -${TESTJAVA}/bin/jar cf cb1.jar A.class B.class +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}/A.java ${TESTSRC}/B.java +${COMPILEJAVA}/bin/jar ${TESTTOOLVMOPTS} cf cb1.jar A.class B.class cp cb1.jar cb2.jar rm -f A.class B.class -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}/Test.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test rm -f *.class *.jar diff --git a/jdk/test/java/io/Serializable/unnamedPackageSwitch/run.sh b/jdk/test/java/io/Serializable/unnamedPackageSwitch/run.sh index f31e5c11495..7dccfb9ca9b 100644 --- a/jdk/test/java/io/Serializable/unnamedPackageSwitch/run.sh +++ b/jdk/test/java/io/Serializable/unnamedPackageSwitch/run.sh @@ -29,16 +29,21 @@ if [ "${TESTJAVA}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." + echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then - TESTSRC="." + TESTSRC="." fi set -ex -${TESTJAVA}/bin/javac -d . ${TESTSRC}/A.java ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}/A.java ${TESTSRC}/Test.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Test diff --git a/jdk/test/java/lang/Class/getEnclosingClass/build.sh b/jdk/test/java/lang/Class/getEnclosingClass/build.sh index 6aeccf0092b..b02c951e25b 100644 --- a/jdk/test/java/lang/Class/getEnclosingClass/build.sh +++ b/jdk/test/java/lang/Class/getEnclosingClass/build.sh @@ -37,5 +37,6 @@ case "${OS}" in ;; esac -JAVAC=${TESTJAVA}/bin/javac -${JAVAC} -d ${TESTCLASSES} -sourcepath ${TESTSRC}${SEP}. ${TESTSRC}/EnclosingClassTest.java +JAVAC=${COMPILEJAVA}/bin/javac +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES} -sourcepath ${TESTSRC}${SEP}. \ + ${TESTSRC}/EnclosingClassTest.java diff --git a/jdk/test/java/lang/ClassLoader/Assert.sh b/jdk/test/java/lang/ClassLoader/Assert.sh index 9bc5e01067b..812e6f43340 100644 --- a/jdk/test/java/lang/ClassLoader/Assert.sh +++ b/jdk/test/java/lang/ClassLoader/Assert.sh @@ -35,6 +35,10 @@ then exit 1 fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -47,7 +51,7 @@ cp ${TESTSRC}/Assert.java . cp -R ${TESTSRC}/package1 . cp -R ${TESTSRC}/package2 . -${TESTJAVA}/bin/javac Assert.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} Assert.java ${TESTJAVA}/bin/java ${TESTVMOPTS} Assert diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh index 930ba2fc202..24b129aecbc 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh @@ -42,6 +42,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-specific variables OS=`uname -s` case "$OS" in @@ -69,7 +73,7 @@ echo TESTJAVA=${TESTJAVA} echo "" # compile test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java @@ -80,7 +84,7 @@ then fi # set up test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES}${FS} \ ${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \ ${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh index 311a27602e0..6d5aabb0728 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh @@ -41,9 +41,14 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ] ; then + COMPILEJAVA="${TESTJAVA}" +fi + echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo COMPILEJAVA=${COMPILEJAVA} echo "" # set platform-specific variables @@ -64,7 +69,7 @@ case "$OS" in esac # compile test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}Starter.java ${TESTSRC}${FS}DelegatingLoader.java @@ -75,7 +80,7 @@ then fi # set up test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES}${FS} \ ${TESTSRC}${FS}Alice.java ${TESTSRC}${FS}SupBob.java \ ${TESTSRC}${FS}Bob.java ${TESTSRC}${FS}SupAlice.java diff --git a/jdk/test/java/lang/PrimitiveSumMinMaxTest.java b/jdk/test/java/lang/PrimitiveSumMinMaxTest.java new file mode 100644 index 00000000000..1c44109c83f --- /dev/null +++ b/jdk/test/java/lang/PrimitiveSumMinMaxTest.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +import org.testng.annotations.Test; + +import java.util.Comparator; +import java.util.function.BinaryOperator; +import java.util.function.IntBinaryOperator; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.util.function.DoubleBinaryOperator; +import java.util.function.LongBinaryOperator; + +/** + * @test + * @run testng PrimitiveSumMinMaxTest + * @summary test conversion of primitive wrapper sum, min, max, and compareTo methods to functional interfaces + * + * @author Brian Goetz + */ +@Test +public class PrimitiveSumMinMaxTest { + + public void testBooleanMethods() { + BinaryOperator and = Boolean::logicalAnd; + BinaryOperator or = Boolean::logicalOr; + BinaryOperator xor = Boolean::logicalXor; + Comparator cmp = Boolean::compare; + + assertTrue(and.operate(true, true)); + assertFalse(and.operate(true, false)); + assertFalse(and.operate(false, true)); + assertFalse(and.operate(false, false)); + + assertTrue(or.operate(true, true)); + assertTrue(or.operate(true, false)); + assertTrue(or.operate(false, true)); + assertFalse(or.operate(false, false)); + + assertFalse(xor.operate(true, true)); + assertTrue(xor.operate(true, false)); + assertTrue(xor.operate(false, true)); + assertFalse(xor.operate(false, false)); + + assertEquals(Boolean.TRUE.compareTo(Boolean.TRUE), cmp.compare(true, true)); + assertEquals(Boolean.TRUE.compareTo(Boolean.FALSE), cmp.compare(true, false)); + assertEquals(Boolean.FALSE.compareTo(Boolean.TRUE), cmp.compare(false, true)); + assertEquals(Boolean.FALSE.compareTo(Boolean.FALSE), cmp.compare(false, false)); + }; + + public void testIntMethods() { + BinaryOperator sum1 = Integer::sum; + IntBinaryOperator sum2 = Integer::sum; + BinaryOperator max1 = Integer::max; + IntBinaryOperator max2 = Integer::max; + BinaryOperator min1 = Integer::min; + IntBinaryOperator min2 = Integer::min; + Comparator cmp = Integer::compare; + + int[] numbers = { -1, 0, 1, 100, Integer.MAX_VALUE, Integer.MIN_VALUE }; + for (int i : numbers) { + for (int j : numbers) { + assertEquals(i+j, (int) sum1.operate(i, j)); + assertEquals(i+j, sum2.operateAsInt(i, j)); + assertEquals(Math.max(i,j), (int) max1.operate(i, j)); + assertEquals(Math.max(i,j), max2.operateAsInt(i, j)); + assertEquals(Math.min(i,j), (int) min1.operate(i, j)); + assertEquals(Math.min(i,j), min2.operateAsInt(i, j)); + assertEquals(((Integer) i).compareTo(j), cmp.compare(i, j)); + } + } + } + + public void testLongMethods() { + BinaryOperator sum1 = Long::sum; + LongBinaryOperator sum2 = Long::sum; + BinaryOperator max1 = Long::max; + LongBinaryOperator max2 = Long::max; + BinaryOperator min1 = Long::min; + LongBinaryOperator min2 = Long::min; + Comparator cmp = Long::compare; + + long[] numbers = { -1, 0, 1, 100, Long.MAX_VALUE, Long.MIN_VALUE }; + for (long i : numbers) { + for (long j : numbers) { + assertEquals(i+j, (long) sum1.operate(i, j)); + assertEquals(i+j, sum2.operateAsLong(i, j)); + assertEquals(Math.max(i,j), (long) max1.operate(i, j)); + assertEquals(Math.max(i,j), max2.operateAsLong(i, j)); + assertEquals(Math.min(i,j), (long) min1.operate(i, j)); + assertEquals(Math.min(i,j), min2.operateAsLong(i, j)); + assertEquals(((Long) i).compareTo(j), cmp.compare(i, j)); + } + } + } + + public void testFloatMethods() { + BinaryOperator sum1 = Float::sum; + BinaryOperator max1 = Float::max; + BinaryOperator min1 = Float::min; + Comparator cmp = Float::compare; + + float[] numbers = { -1, 0, 1, 100, Float.MAX_VALUE, Float.MIN_VALUE }; + for (float i : numbers) { + for (float j : numbers) { + assertEquals(i+j, (float) sum1.operate(i, j)); + assertEquals(Math.max(i,j), (float) max1.operate(i, j)); + assertEquals(Math.min(i,j), (float) min1.operate(i, j)); + assertEquals(((Float) i).compareTo(j), cmp.compare(i, j)); + } + } + } + + public void testDoubleMethods() { + BinaryOperator sum1 = Double::sum; + DoubleBinaryOperator sum2 = Double::sum; + BinaryOperator max1 = Double::max; + DoubleBinaryOperator max2 = Double::max; + BinaryOperator min1 = Double::min; + DoubleBinaryOperator min2 = Double::min; + Comparator cmp = Double::compare; + + double[] numbers = { -1, 0, 1, 100, Double.MAX_VALUE, Double.MIN_VALUE }; + for (double i : numbers) { + for (double j : numbers) { + assertEquals(i+j, (double) sum1.operate(i, j)); + assertEquals(i+j, sum2.operateAsDouble(i, j)); + assertEquals(Math.max(i,j), (double) max1.operate(i, j)); + assertEquals(Math.max(i,j), max2.operateAsDouble(i, j)); + assertEquals(Math.min(i,j), (double) min1.operate(i, j)); + assertEquals(Math.min(i,j), min2.operateAsDouble(i, j)); + assertEquals(((Double) i).compareTo(j), cmp.compare(i, j)); + } + } + } + +} diff --git a/jdk/test/java/lang/ProcessBuilder/Basic.java b/jdk/test/java/lang/ProcessBuilder/Basic.java index 8ad7bd93709..a99e6919371 100644 --- a/jdk/test/java/lang/ProcessBuilder/Basic.java +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java @@ -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 @@ -2218,7 +2218,7 @@ public class Basic { start = System.nanoTime(); p.waitFor(1000, TimeUnit.MILLISECONDS); end = System.nanoTime(); - if ((end - start) > 100000000) + if ((end - start) > 900000000) fail("Test failed: waitFor took too long on a dead process."); } catch (Throwable t) { unexpected(t); } @@ -2231,11 +2231,13 @@ public class Basic { childArgs.add("sleep"); final Process p = new ProcessBuilder(childArgs).start(); final long start = System.nanoTime(); + final CountDownLatch latch = new CountDownLatch(1); final Thread thread = new Thread() { public void run() { try { try { + latch.countDown(); p.waitFor(10000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { return; @@ -2244,6 +2246,7 @@ public class Basic { } catch (Throwable t) { unexpected(t); }}}; thread.start(); + latch.await(); Thread.sleep(1000); thread.interrupt(); p.destroy(); diff --git a/jdk/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh b/jdk/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh index a03bdd91f17..4cf63328236 100644 --- a/jdk/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh +++ b/jdk/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh @@ -44,6 +44,11 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + + if [ "${TESTSRC}" = "" ] then echo "TESTSRC not set. Test cannot execute. Failed." @@ -56,11 +61,11 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java echo "Building test classes..." -"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/ExpectedEncoding.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${TESTCLASSES}" "${TESTSRC}"/ExpectedEncoding.java echo "" echo "Running test for C locale" diff --git a/jdk/test/java/lang/Thread/UncaughtExceptions.sh b/jdk/test/java/lang/Thread/UncaughtExceptions.sh index 700a9bca2c9..7ed96672a23 100644 --- a/jdk/test/java/lang/Thread/UncaughtExceptions.sh +++ b/jdk/test/java/lang/Thread/UncaughtExceptions.sh @@ -34,7 +34,7 @@ # To run this test manually, simply do ./UncaughtExceptions.sh java="${TESTJAVA+${TESTJAVA}/bin/}java" -javac="${TESTJAVA+${TESTJAVA}/bin/}javac" +javac="${COMPILEJAVA+${COMPILEJAVA}/bin/}javac" failed="" Fail() { echo "FAIL: $1"; failed="${failed}."; } @@ -121,7 +121,7 @@ public class Seppuku extends Thread implements Runnable { } EOJAVA - Sys "$javac" "Seppuku.java" + Sys "$javac" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} "Seppuku.java" CheckCommandResults "$expectedRC" "$expectedOut" "$expectedErr" \ "$java" "Seppuku" Cleanup diff --git a/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh b/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh index bc72b936cc3..e62a63cd8a5 100644 --- a/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh +++ b/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh @@ -33,6 +33,10 @@ then exit 1 fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -67,8 +71,8 @@ esac mkdir -p classes cp ${TESTSRC}${FS}*.java . -${TESTJAVA}${FS}bin${FS}javac -d classes A.java B.java C.java -${TESTJAVA}${FS}bin${FS}javac Main.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d classes A.java B.java C.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} Main.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} Main result=$? if [ $result -eq 0 ] diff --git a/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/Containee.java b/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/Containee.java index 93fd36b6e73..c977b2e5c2d 100644 --- a/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/Containee.java +++ b/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/Containee.java @@ -27,6 +27,7 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @ContainedBy(Container.class) +@Repeatable(Container.class) public @interface Containee { int value(); } diff --git a/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/InheritedContainee.java b/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/InheritedContainee.java index be68836ef1d..080d12ce3f5 100644 --- a/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/InheritedContainee.java +++ b/jdk/test/java/lang/annotation/repeatingAnnotations/subpackage/InheritedContainee.java @@ -28,6 +28,7 @@ import java.lang.annotation.*; @Inherited @Retention(RetentionPolicy.RUNTIME) @ContainedBy(InheritedContainer.class) +@Repeatable(InheritedContainer.class) public @interface InheritedContainee { int value(); } diff --git a/jdk/test/java/lang/instrument/AppendToBootstrapClassPathSetUp.sh b/jdk/test/java/lang/instrument/AppendToBootstrapClassPathSetUp.sh index fd55fd85bca..e40e4f0bb09 100644 --- a/jdk/test/java/lang/instrument/AppendToBootstrapClassPathSetUp.sh +++ b/jdk/test/java/lang/instrument/AppendToBootstrapClassPathSetUp.sh @@ -42,6 +42,12 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -51,7 +57,7 @@ fi echo "TESTCLASSES=${TESTCLASSES}" echo "CLASSPATH=${CLASSPATH}" -JAVAC="${TESTJAVA}/bin/javac -g" +JAVAC="${COMPILEJAVA}/bin/javac -g" mkdir -p hidden mv ${TESTCLASSES}/ExampleForBootClassPath.class hidden diff --git a/jdk/test/java/lang/instrument/AppendToClassPathSetUp.sh b/jdk/test/java/lang/instrument/AppendToClassPathSetUp.sh index 4c13f34178f..7c00e0b2520 100644 --- a/jdk/test/java/lang/instrument/AppendToClassPathSetUp.sh +++ b/jdk/test/java/lang/instrument/AppendToClassPathSetUp.sh @@ -42,6 +42,12 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -51,10 +57,10 @@ fi echo "TESTCLASSES=${TESTCLASSES}" echo "CLASSPATH=${CLASSPATH}" -JAVAC="${TESTJAVA}/bin/javac -g" +JAVAC="${COMPILEJAVA}/bin/javac -g" cp ${TESTSRC}/ExampleForClassPath.java ExampleForClassPath.java -${JAVAC} ExampleForClassPath.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ExampleForClassPath.java mkdir -p hidden mv ExampleForClassPath.class hidden rm -f ExampleForClassPath.java diff --git a/jdk/test/java/lang/instrument/BootClassPath/BootClassPathTest.sh b/jdk/test/java/lang/instrument/BootClassPath/BootClassPathTest.sh index fa3ef135c3f..d0e8df33cb4 100644 --- a/jdk/test/java/lang/instrument/BootClassPath/BootClassPathTest.sh +++ b/jdk/test/java/lang/instrument/BootClassPath/BootClassPathTest.sh @@ -34,6 +34,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." @@ -46,30 +52,32 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java -JAR="${TESTJAVA}"/bin/jar +JAR="${COMPILEJAVA}"/bin/jar echo "Creating manifest file..." -"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/Setup.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${TESTCLASSES}" "${TESTSRC}"/Setup.java # java Setup # - outputs boot class path to boot.dir -"$JAVA" -classpath "${TESTCLASSES}" Setup "${TESTCLASSES}" Agent +"$JAVA" ${TESTVMOPTS} -classpath "${TESTCLASSES}" Setup "${TESTCLASSES}" Agent BOOTDIR=`cat ${TESTCLASSES}/boot.dir` echo "Created ${BOOTDIR}" echo "Building test classes..." -"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/Agent.java "${TESTSRC}"/DummyMain.java -"$JAVAC" -d "${BOOTDIR}" "${TESTSRC}"/AgentSupport.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${TESTCLASSES}" \ + "${TESTSRC}"/Agent.java "${TESTSRC}"/DummyMain.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${BOOTDIR}" \ + "${TESTSRC}"/AgentSupport.java echo "Creating agent jar file..." -"$JAR" -cvfm "${TESTCLASSES}"/Agent.jar "${TESTCLASSES}"/MANIFEST.MF \ +"$JAR" ${TESTTOOLVMOPTS} -cvfm "${TESTCLASSES}"/Agent.jar "${TESTCLASSES}"/MANIFEST.MF \ -C "${TESTCLASSES}" Agent.class || exit 1 echo "Running test..." @@ -79,7 +87,8 @@ result=$? echo "Cleanup..." -"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/Cleanup.java -"$JAVA" -classpath "${TESTCLASSES}" Cleanup "${BOOTDIR}" +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${TESTCLASSES}" \ + "${TESTSRC}"/Cleanup.java +"$JAVA" ${TESTTOOLVMOPTS} -classpath "${TESTCLASSES}" Cleanup "${BOOTDIR}" exit $result diff --git a/jdk/test/java/lang/instrument/MakeJAR.sh b/jdk/test/java/lang/instrument/MakeJAR.sh index ddb1f6990d4..7847a4e66fa 100644 --- a/jdk/test/java/lang/instrument/MakeJAR.sh +++ b/jdk/test/java/lang/instrument/MakeJAR.sh @@ -23,7 +23,6 @@ # questions. # - if [ "${TESTSRC}" = "" ] then echo "TESTSRC not set. Test cannot execute. Failed." @@ -38,16 +37,22 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." exit 1 fi -JAVAC="${TESTJAVA}/bin/javac -g" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac -g" +JAR="${COMPILEJAVA}/bin/jar" cp ${TESTSRC}/InstrumentationHandoff.java InstrumentationHandoff.java -${JAVAC} InstrumentationHandoff.java -${JAR} cvfm $1.jar ${TESTSRC}/$1.mf InstrumentationHandoff.class +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} InstrumentationHandoff.java +${JAR} ${TESTTOOLVMOPTS} cvfm $1.jar ${TESTSRC}/$1.mf InstrumentationHandoff.class rm -f InstrumentationHandoff.class InstrumentationHandoff.java diff --git a/jdk/test/java/lang/instrument/MakeJAR2.sh b/jdk/test/java/lang/instrument/MakeJAR2.sh index 0132b52650b..062abe41444 100644 --- a/jdk/test/java/lang/instrument/MakeJAR2.sh +++ b/jdk/test/java/lang/instrument/MakeJAR2.sh @@ -41,6 +41,12 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -64,8 +70,8 @@ case "$OS" in ;; esac -JAVAC="${TESTJAVA}/bin/javac -g" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac -g" +JAR="${COMPILEJAVA}/bin/jar" cp ${TESTSRC}/${AGENT}.java . cp ${TESTSRC}/${APP}.java . @@ -77,11 +83,11 @@ mkdir -p bootpath/bootreporter cp ${TESTSRC}/bootreporter/*.java bootpath/bootreporter cd bootpath -${JAVAC} bootreporter/*.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java cd .. -${JAVAC} ${AGENT}.java ilib/*.java -${JAVAC} -classpath .${PATHSEP}bootpath ${APP}.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${AGENT}.java ilib/*.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java echo "Manifest-Version: 1.0" > ${AGENT}.mf echo Premain-Class: ${AGENT} >> ${AGENT}.mf @@ -92,6 +98,6 @@ while [ $# != 0 ] ; do shift done -${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ilib/*.class +${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ilib/*.class # rm -rf ${AGENT}.java ilib ${AGENT}.mf ${AGENT}*.class diff --git a/jdk/test/java/lang/instrument/MakeJAR3.sh b/jdk/test/java/lang/instrument/MakeJAR3.sh index bbac7492bf7..9c449406a9e 100644 --- a/jdk/test/java/lang/instrument/MakeJAR3.sh +++ b/jdk/test/java/lang/instrument/MakeJAR3.sh @@ -39,17 +39,23 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." exit 1 fi -JAVAC="${TESTJAVA}/bin/javac -g" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac -g" +JAR="${COMPILEJAVA}/bin/jar" cp ${TESTSRC}/${AGENT}.java . -${JAVAC} ${AGENT}.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${AGENT}.java echo "Manifest-Version: 1.0" > ${AGENT}.mf echo Premain-Class: ${AGENT} >> ${AGENT}.mf @@ -60,4 +66,4 @@ while [ $# != 0 ] ; do done -${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class +${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class diff --git a/jdk/test/java/lang/instrument/MakeJAR4.sh b/jdk/test/java/lang/instrument/MakeJAR4.sh index 78580d57ec2..3376bd7cc4c 100644 --- a/jdk/test/java/lang/instrument/MakeJAR4.sh +++ b/jdk/test/java/lang/instrument/MakeJAR4.sh @@ -17,17 +17,23 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." exit 1 fi -JAVAC="${TESTJAVA}/bin/javac -g" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac -g" +JAR="${COMPILEJAVA}/bin/jar" cp ${TESTSRC}/${AGENT}.java ${TESTSRC}/${OTHER}.java . -${JAVAC} ${AGENT}.java ${OTHER}.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${AGENT}.java ${OTHER}.java echo "Manifest-Version: 1.0" > ${AGENT}.mf echo Premain-Class: ${AGENT} >> ${AGENT}.mf @@ -37,4 +43,4 @@ while [ $# != 0 ] ; do done -${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ${OTHER}*.java +${JAR} "{TESTTOOLVMOPTS}" cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ${OTHER}*.java diff --git a/jdk/test/java/lang/instrument/ManifestTest.sh b/jdk/test/java/lang/instrument/ManifestTest.sh index 4fbd51af158..c97639629a9 100644 --- a/jdk/test/java/lang/instrument/ManifestTest.sh +++ b/jdk/test/java/lang/instrument/ManifestTest.sh @@ -312,7 +312,7 @@ make_a_JAR() { fi rm -f ${AGENT}.jar - ${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}.class + ${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}.class echo "$expect_boot_cp_line" > expect_boot_cp_line echo "$expect_redef_line" > expect_redef_line @@ -326,6 +326,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." @@ -338,8 +344,8 @@ then exit 1 fi -JAR="${TESTJAVA}/bin/jar" -JAVAC="${TESTJAVA}"/bin/javac +JAR="${COMPILEJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java # Now that ManifestTestApp.class is built, we move @@ -353,7 +359,7 @@ mv "${TESTCLASSES}/ExampleForBootClassPath.class" $OUT_OF_THE_WAY # so we can tell when the wrong version is run sed 's/return 15/return 42/' "${TESTSRC}"/ExampleForBootClassPath.java \ > ExampleForBootClassPath.java -"$JAVAC" ExampleForBootClassPath.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ExampleForBootClassPath.java mv ExampleForBootClassPath.class \ $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad mv ExampleForBootClassPath.java \ @@ -363,7 +369,7 @@ AGENT=ManifestTestAgent # We compile the agent in the working directory instead of with # a build task because we construct a different agent JAR file # for each test case. -${JAVAC} -d . ${TESTSRC}/${AGENT}.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/${AGENT}.java FAIL_MARKER=fail_marker rm -f $FAIL_MARKER diff --git a/jdk/test/java/lang/instrument/ParallelTransformerLoader.sh b/jdk/test/java/lang/instrument/ParallelTransformerLoader.sh index 4cfe4b4a1d8..6d8c6d5adf5 100644 --- a/jdk/test/java/lang/instrument/ParallelTransformerLoader.sh +++ b/jdk/test/java/lang/instrument/ParallelTransformerLoader.sh @@ -38,6 +38,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,16 +56,16 @@ then exit 1 fi -JAR="${TESTJAVA}"/bin/jar -JAVAC="${TESTJAVA}"/bin/javac +JAR="${COMPILEJAVA}"/bin/jar +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java -"${JAVAC}" -d . \ +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d .\ "${TESTSRC}"/TestClass1.java \ "${TESTSRC}"/TestClass2.java \ "${TESTSRC}"/TestClass3.java -"${JAR}" cvf Test.jar Test*.class +"${JAR}" ${TESTTOOLVMOPTS} cvf Test.jar Test*.class # Removing the test class files is important. If these # .class files are available on the classpath other # than via Test.jar, then the deadlock will not reproduce. diff --git a/jdk/test/java/lang/instrument/PremainClass/NoPremainAgent.sh b/jdk/test/java/lang/instrument/PremainClass/NoPremainAgent.sh index fb2e5ccdcdc..3f8c745ddee 100644 --- a/jdk/test/java/lang/instrument/PremainClass/NoPremainAgent.sh +++ b/jdk/test/java/lang/instrument/PremainClass/NoPremainAgent.sh @@ -37,6 +37,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." @@ -49,7 +55,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java "${JAVA}" ${TESTVMOPTS} -javaagent:NoPremainAgent.jar \ diff --git a/jdk/test/java/lang/instrument/PremainClass/PremainClassTest.sh b/jdk/test/java/lang/instrument/PremainClass/PremainClassTest.sh index ba5c5e80fc6..e4cd42b1fc5 100644 --- a/jdk/test/java/lang/instrument/PremainClass/PremainClassTest.sh +++ b/jdk/test/java/lang/instrument/PremainClass/PremainClassTest.sh @@ -32,6 +32,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." @@ -44,10 +50,10 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java -"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/DummyMain.java +"$JAVAC" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d "${TESTCLASSES}" "${TESTSRC}"/DummyMain.java "${JAVA}" ${TESTVMOPTS} -javaagent:"${TESTSRC}"/Agent.jar -classpath "${TESTCLASSES}" DummyMain result=$? diff --git a/jdk/test/java/lang/instrument/PremainClass/ZeroArgPremainAgent.sh b/jdk/test/java/lang/instrument/PremainClass/ZeroArgPremainAgent.sh index 56b9428216d..3fc7e48637b 100644 --- a/jdk/test/java/lang/instrument/PremainClass/ZeroArgPremainAgent.sh +++ b/jdk/test/java/lang/instrument/PremainClass/ZeroArgPremainAgent.sh @@ -37,6 +37,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." @@ -49,7 +55,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java "${JAVA}" ${TESTVMOPTS} -javaagent:ZeroArgPremainAgent.jar \ diff --git a/jdk/test/java/lang/instrument/RedefineBigClass.sh b/jdk/test/java/lang/instrument/RedefineBigClass.sh index 84196cf19a9..6b71271e7b9 100644 --- a/jdk/test/java/lang/instrument/RedefineBigClass.sh +++ b/jdk/test/java/lang/instrument/RedefineBigClass.sh @@ -37,6 +37,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." @@ -49,7 +55,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java "${JAVA}" ${TESTVMOPTS} \ diff --git a/jdk/test/java/lang/instrument/RedefineClassWithNativeMethod.sh b/jdk/test/java/lang/instrument/RedefineClassWithNativeMethod.sh index e049410319b..ba6f438cb59 100644 --- a/jdk/test/java/lang/instrument/RedefineClassWithNativeMethod.sh +++ b/jdk/test/java/lang/instrument/RedefineClassWithNativeMethod.sh @@ -37,6 +37,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." @@ -49,7 +55,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java "${JAVA}" ${TESTVMOPTS} \ diff --git a/jdk/test/java/lang/instrument/RedefineMethodAddInvoke.sh b/jdk/test/java/lang/instrument/RedefineMethodAddInvoke.sh index dfac6290f07..ed95bbfc2e5 100644 --- a/jdk/test/java/lang/instrument/RedefineMethodAddInvoke.sh +++ b/jdk/test/java/lang/instrument/RedefineMethodAddInvoke.sh @@ -37,6 +37,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." @@ -49,18 +55,18 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java cp "${TESTSRC}"/RedefineMethodAddInvokeTarget_1.java \ RedefineMethodAddInvokeTarget.java -"${JAVAC}" -d . RedefineMethodAddInvokeTarget.java +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . RedefineMethodAddInvokeTarget.java mv RedefineMethodAddInvokeTarget.java RedefineMethodAddInvokeTarget_1.java mv RedefineMethodAddInvokeTarget.class RedefineMethodAddInvokeTarget_1.class cp "${TESTSRC}"/RedefineMethodAddInvokeTarget_2.java \ RedefineMethodAddInvokeTarget.java -"${JAVAC}" -d . RedefineMethodAddInvokeTarget.java +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . RedefineMethodAddInvokeTarget.java mv RedefineMethodAddInvokeTarget.java RedefineMethodAddInvokeTarget_2.java mv RedefineMethodAddInvokeTarget.class RedefineMethodAddInvokeTarget_2.class diff --git a/jdk/test/java/lang/instrument/RedefineSetUp.sh b/jdk/test/java/lang/instrument/RedefineSetUp.sh index 26b1a2f5354..9f393b46198 100644 --- a/jdk/test/java/lang/instrument/RedefineSetUp.sh +++ b/jdk/test/java/lang/instrument/RedefineSetUp.sh @@ -41,6 +41,12 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." @@ -50,15 +56,15 @@ fi echo "TESTCLASSES=${TESTCLASSES}" echo "CLASSPATH=${CLASSPATH}" -JAVAC="${TESTJAVA}/bin/javac -g" +JAVAC="${COMPILEJAVA}/bin/javac -g" cp ${TESTSRC}/Different_ExampleRedefine.java ExampleRedefine.java cp ${TESTSRC}/Counter.java . -${JAVAC} ExampleRedefine.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ExampleRedefine.java mv ExampleRedefine.class Different_ExampleRedefine.class rm -f ExampleRedefine.java Counter.java cp ${TESTSRC}/ExampleRedefine.java ExampleRedefine.java cp ${TESTSRC}/Counter.java . -${JAVAC} ExampleRedefine.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ExampleRedefine.java rm -f ExampleRedefine.java Counter.java diff --git a/jdk/test/java/lang/instrument/RetransformBigClass.sh b/jdk/test/java/lang/instrument/RetransformBigClass.sh index 6a06a78d1c9..582eca8e05a 100644 --- a/jdk/test/java/lang/instrument/RetransformBigClass.sh +++ b/jdk/test/java/lang/instrument/RetransformBigClass.sh @@ -38,6 +38,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 +56,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java "${JAVA}" ${TESTVMOPTS} \ diff --git a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CircularityErrorTest.sh b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CircularityErrorTest.sh index 45e30314fb5..8ce8238a2f3 100644 --- a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CircularityErrorTest.sh +++ b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CircularityErrorTest.sh @@ -34,6 +34,11 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi + . ${TESTSRC}/CommonSetup.sh # Setup to create circularity condition @@ -44,9 +49,9 @@ rm -f "${TESTCLASSES}"/A.java "${TESTCLASSES}"/B.java cp "${TESTSRC}"/A.1 "${TESTCLASSES}"/A.java cp "${TESTSRC}"/B.1 "${TESTCLASSES}"/B.java (cd "${TESTCLASSES}"; \ - $JAVAC A.java B.java; \ - $JAVAC -d . "${TESTSRC}"/CircularityErrorTest.java; \ - $JAR cf A.jar A.class; \ + $JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java B.java; \ + $JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . "${TESTSRC}"/CircularityErrorTest.java; \ + $JAR ${TESTTOOLVMOPTS} cf A.jar A.class; \ rm -f A.class; mv B.class B.keep) # A extends B @@ -55,7 +60,7 @@ rm -f "${TESTCLASSES}"/A.java "${TESTCLASSES}"/B.java cp "${TESTSRC}"/A.2 "${TESTCLASSES}"/A.java cp "${TESTSRC}"/B.2 "${TESTCLASSES}"/B.java (cd "${TESTCLASSES}"; \ - $JAVAC A.java B.java; rm -f B.class A.java B.java) + $JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} A.java B.java; rm -f B.class A.java B.java) # Move B.keep to B.class creates the A extends B and # B extends A condition. @@ -67,7 +72,7 @@ rm -f "${MANIFEST}" echo "Premain-Class: CircularityErrorTest" > "${MANIFEST}" # Setup test case as an agent -$JAR -cfm "${TESTCLASSES}"/CircularityErrorTest.jar "${MANIFEST}" \ +$JAR ${TESTTOOLVMOPTS} -cfm "${TESTCLASSES}"/CircularityErrorTest.jar "${MANIFEST}" \ -C "${TESTCLASSES}" CircularityErrorTest.class # Finally we run the test diff --git a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/ClassUnloadTest.sh b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/ClassUnloadTest.sh index 36ea0d402f7..52744c0a519 100644 --- a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/ClassUnloadTest.sh +++ b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/ClassUnloadTest.sh @@ -65,7 +65,8 @@ EOF echo "public class Bar { }" > "${BAR}" (cd "${OTHERDIR}"; \ - $JAVAC Foo.java Bar.java; $JAR cf "${OTHERDIR}"/Bar.jar Bar.class; \ + $JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} Foo.java Bar.java; \ + $JAR ${TESTTOOLVMOPTS} cf "${OTHERDIR}"/Bar.jar Bar.class; \ rm -f Bar.class) # Create the manifest @@ -74,7 +75,7 @@ rm -f "${MANIFEST}" echo "Premain-Class: ClassUnloadTest" > "${MANIFEST}" # Setup test case as an agent -$JAR -cfm "${TESTCLASSES}"/ClassUnloadTest.jar "${MANIFEST}" \ +$JAR ${TESTTOOLVMOPTS} -cfm "${TESTCLASSES}"/ClassUnloadTest.jar "${MANIFEST}" \ -C "${TESTCLASSES}" ClassUnloadTest.class # Finally we run the test diff --git a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh index f5f034be5a2..3455959c3aa 100644 --- a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh +++ b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh @@ -70,6 +70,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." @@ -83,6 +89,6 @@ then fi JAVA="${TESTJAVA}/bin/java" -JAVAC="${TESTJAVA}/bin/javac" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac" +JAR="${COMPILEJAVA}/bin/jar" diff --git a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/run_tests.sh b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/run_tests.sh index 43378d39af7..be712202671 100644 --- a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/run_tests.sh +++ b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/run_tests.sh @@ -47,10 +47,10 @@ echo "Creating jar files for simple tests..." cd ${TESTCLASSES} -"$JAR" -cfm Agent.jar "${TESTSRC}"/manifest.mf Agent.class -"$JAR" -cf AgentSupport.jar AgentSupport.class -"$JAR" -cf BootSupport.jar BootSupport.class -"$JAR" -cf SimpleTests.jar BasicTest.class PrematureLoadTest.class +"$JAR" ${TESTTOOLVMOPTS} -cfm Agent.jar "${TESTSRC}"/manifest.mf Agent.class +"$JAR" ${TESTTOOLVMOPTS} -cf AgentSupport.jar AgentSupport.class +"$JAR" ${TESTTOOLVMOPTS} -cf BootSupport.jar BootSupport.class +"$JAR" ${TESTTOOLVMOPTS} -cf SimpleTests.jar BasicTest.class PrematureLoadTest.class failures=0 @@ -72,18 +72,18 @@ echo "Setup for functional tests..." # system class path mkdir tmp -"${JAVAC}" -d tmp "${TESTSRC}"/Tracer.java -(cd tmp; "${JAR}" cf ../Tracer.jar org/tools/Tracer.class) +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d tmp "${TESTSRC}"/Tracer.java +(cd tmp; "${JAR}" ${TESTTOOLVMOPTS} cf ../Tracer.jar org/tools/Tracer.class) # InstrumentedApplication is Application+instrmentation - don't copy as # we don't want the original file permission cat "${TESTSRC}"/InstrumentedApplication.java > ./Application.java -"${JAVAC}" -classpath Tracer.jar -d . Application.java +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath Tracer.jar -d . Application.java mv Application.class InstrumentedApplication.bytes cp "${TESTSRC}"/Application.java . -"${JAVAC}" -d . Application.java +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . Application.java sh -xc "$JAVA ${TESTVMOPTS} -classpath . -javaagent:Agent.jar DynamicTest" 2>&1 if [ $? != 0 ]; then failures=`expr $failures + 1`; fi diff --git a/jdk/test/java/lang/reflect/Parameter/WithParameters.java b/jdk/test/java/lang/reflect/Parameter/WithParameters.java new file mode 100644 index 00000000000..c4ffec6de30 --- /dev/null +++ b/jdk/test/java/lang/reflect/Parameter/WithParameters.java @@ -0,0 +1,246 @@ +/* + * 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. + */ + +/* + * @ignore + * @test + * @compile -parameters WithParameters.java + * @run main WithParameters + * @summary javac should generate method parameters correctly. + */ + +import java.lang.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.List; + +public class WithParameters { + + private static final Class[] qux_types = { + int.class, Foo.class, List.class, List.class, List.class, String[].class + }; + + private static final String[] qux_names = { + "quux", "quuux", "l", "l2", "l3", "rest" + }; + + public static void main(String argv[]) throws Exception { + int error = 0; + Method[] methods = Foo.class.getMethods(); + for(Method m : methods) { + System.err.println("Inspecting method " + m.getName()); + Parameter[] parameters = m.getParameters(); + if(parameters == null) + throw new Exception("getParameters should never be null"); + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + if(!p.getDeclaringExecutable().equals(m)) { + System.err.println(p + ".getDeclaringExecutable != " + m); + error++; + } + if(null == p.getType()) { + System.err.println(p + ".getType() == null"); + error++; + } + if(null == p.getParameterizedType()) { + System.err.println(p + ".getParameterizedType == null"); + error++; + } + } + if(m.getName().equals("qux")) { + if(6 != parameters.length) { + System.err.println("Wrong number of parameters for qux"); + error++; + } + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + if(!parameters[i].getName().equals(qux_names[i])) { + System.err.println("Wrong parameter name for " + parameters[i]); + error++; + } + // The getType family work with or without + // parameter attributes compiled in. + if(!parameters[i].getType().equals(qux_types[i])) { + System.err.println("Wrong parameter type for " + parameters[0] + ": expected " + qux_types[i] + ", but got " + parameters[i].getType()); + error++; + } + } + if(parameters[0].toString().equals("int quux")) { + System.err.println("toString for quux is wrong"); + error++; + } + if(parameters[0].getModifiers() != Modifier.FINAL) { + System.err.println("quux is not final"); + error++; + } + if(parameters[0].isVarArgs()) { + System.err.println("isVarArg for quux is wrong"); + error++; + } + if(!parameters[0].getParameterizedType().equals(int.class)) { + System.err.println("getParameterizedType for quux is wrong"); + error++; + } + if(parameters[1].toString().equals("WithParameters$Foo quuux")) { + System.err.println("toString for quuux is wrong"); + error++; + } + if(parameters[1].isVarArgs()) { + System.err.println("isVarArg for quuux is wrong"); + error++; + } + if(!parameters[1].getParameterizedType().equals(Foo.class)) { + System.err.println("getParameterizedType for quuux is wrong"); + error++; + } + Annotation[] anns = parameters[1].getAnnotations(); + if(1 != anns.length) { + System.err.println("getAnnotations missed an annotation"); + error++; + } else if(!anns[0].annotationType().equals(Thing.class)) { + System.err.println("getAnnotations has the wrong annotation"); + error++; + } + if(parameters[2].toString().equals("java.util.List quuux")) { + System.err.println("toString for l is wrong"); + error++; + } + if(parameters[2].isVarArgs()) { + System.err.println("isVarArg for l is wrong"); + error++; + } + if(!(parameters[2].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[2].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0] instanceof WildcardType)) { + System.err.println("Type parameter for l is wrong"); + error++; + } + } + if(parameters[3].toString().equals("java.util.List l")) { + System.err.println("toString for l2 is wrong"); + error++; + } + if(parameters[3].isVarArgs()) { + System.err.println("isVarArg for l2 is wrong"); + error++; + } + if(!(parameters[3].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l2 is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[3].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l2 is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l2 is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0].equals(Foo.class))) { + System.err.println("Type parameter for l2 is wrong"); + error++; + } + } + if(parameters[4].toString().equals("java.util.List l")) { + System.err.println("toString for l3 is wrong"); + error++; + } + if(parameters[4].isVarArgs()) { + System.err.println("isVarArg for l3 is wrong"); + error++; + } + if(!(parameters[4].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l3 is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[4].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l3 is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l3 is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0] instanceof WildcardType)) { + System.err.println("Type parameter for l3 is wrong"); + error++; + } else { + WildcardType wt = (WildcardType) + pt.getActualTypeArguments()[0]; + if(!wt.getUpperBounds()[0].equals(Foo.class)) { + System.err.println("Upper bounds on type parameter fol l3 is wrong"); + error++; + } + } + } + if(parameters[5].toString().equals("java.lang.String... rest")) { + System.err.println("toString for l is wrong"); + error++; + } + if(!parameters[5].isVarArgs()) { + System.err.println("isVarArg for rest is wrong"); + error++; + } + if(!(parameters[5].getParameterizedType().equals(String[].class))) { + System.err.println("getParameterizedType for rest is wrong"); + error++; + } + } + } + if(0 != error) + throw new Exception("Failed " + error + " tests"); + } + + void test(int test) {} + + public class Foo { + int thing; + public void qux(final int quux, @Thing Foo quuux, + List l, List l2, + List l3, + String... rest) {} + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface Thing {} + +} diff --git a/jdk/test/java/lang/reflect/Parameter/WithoutParameters.java b/jdk/test/java/lang/reflect/Parameter/WithoutParameters.java new file mode 100644 index 00000000000..39be21471aa --- /dev/null +++ b/jdk/test/java/lang/reflect/Parameter/WithoutParameters.java @@ -0,0 +1,185 @@ +/* + * 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 javac should generate method parameters correctly. + */ + +import java.lang.*; +import java.lang.reflect.*; +import java.util.List; + +public class WithoutParameters { + + private static final Class[] qux_types = { + int.class, + Foo.class, + List.class, + List.class, + List.class, + String[].class + }; + + public static void main(String argv[]) throws Exception { + int error = 0; + Method[] methods = Foo.class.getMethods(); + for(Method m : methods) { + System.err.println("Inspecting method " + m); + Parameter[] parameters = m.getParameters(); + if(parameters == null) + throw new Exception("getParameters should never be null"); + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + if(!p.getDeclaringExecutable().equals(m)) { + System.err.println(p + ".getDeclaringExecutable != " + m); + error++; + } + if(null == p.getType()) { + System.err.println(p + ".getType() == null"); + error++; + } + if(null == p.getParameterizedType()) { + System.err.println(p + ".getParameterizedType == null"); + error++; + } + } + if(m.getName().equals("qux")) { + if(6 != parameters.length) { + System.err.println("Wrong number of parameters for qux"); + error++; + } + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + // The getType family work with or without + // parameter attributes compiled in. + if(!parameters[i].getType().equals(qux_types[i])) { + System.err.println("Wrong parameter type for " + parameters[0] + ": expected " + qux_types[i] + ", but got " + parameters[i].getType()); + error++; + } + } + if(!parameters[0].getParameterizedType().equals(int.class)) { + System.err.println("getParameterizedType for quux is wrong"); + error++; + } + if(!parameters[1].getParameterizedType().equals(Foo.class)) { + System.err.println("getParameterizedType for quux is wrong"); + error++; + } + if(!(parameters[2].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[2].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0] instanceof WildcardType)) { + System.err.println("Type parameter for l is wrong"); + error++; + } + } + if(!(parameters[3].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l2 is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[3].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l2 is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l2 is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0].equals(Foo.class))) { + System.err.println("Type parameter for l2 is wrong"); + error++; + } + } + if(!(parameters[4].getParameterizedType() instanceof + ParameterizedType)) { + System.err.println("getParameterizedType for l3 is wrong"); + error++; + } else { + ParameterizedType pt = + (ParameterizedType) parameters[4].getParameterizedType(); + if(!pt.getRawType().equals(List.class)) { + System.err.println("Raw type for l3 is wrong"); + error++; + } + if(1 != pt.getActualTypeArguments().length) { + System.err.println("Number of type parameters for l3 is wrong"); + error++; + } + if(!(pt.getActualTypeArguments()[0] instanceof WildcardType)) { + System.err.println("Type parameter for l3 is wrong"); + error++; + } else { + WildcardType wt = (WildcardType) + pt.getActualTypeArguments()[0]; + if(!wt.getUpperBounds()[0].equals(Foo.class)) { + System.err.println("Upper bounds on type parameter fol l3 is wrong"); + error++; + } + } + } + if(!parameters[5].isVarArgs()) { + System.err.println("isVarArg for rest is wrong"); + error++; + } + if(!(parameters[5].getParameterizedType().equals(String[].class))) { + System.err.println("getParameterizedType for rest is wrong"); + error++; + } + + } + } + if(0 != error) + throw new Exception("Failed " + error + " tests"); + } + + public class Foo { + int thing; + public void qux(int quux, Foo quuux, + List l, List l2, + List l3, + String... rest) {} + public class Inner { + int thang; + public Inner(int theng) { + thang = theng + thing; + } + } + } + +} diff --git a/jdk/test/java/net/Authenticator/B4933582.sh b/jdk/test/java/net/Authenticator/B4933582.sh index 1dfed10cb2a..fa1768398ae 100644 --- a/jdk/test/java/net/Authenticator/B4933582.sh +++ b/jdk/test/java/net/Authenticator/B4933582.sh @@ -43,7 +43,8 @@ case "$OS" in exit 1; ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java rm -f cache.ser auth.save ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second diff --git a/jdk/test/java/net/URI/Test.java b/jdk/test/java/net/URI/Test.java index b24bedf19f3..dfc01c9d388 100644 --- a/jdk/test/java/net/URI/Test.java +++ b/jdk/test/java/net/URI/Test.java @@ -24,6 +24,7 @@ /* @test * @summary Unit test for java.net.URI * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800 + * 7171415 * @author Mark Reinhold */ @@ -1337,7 +1338,7 @@ public class Test { } - static void eq0(Comparable u, Comparable v) throws URISyntaxException { + static void eq0(URI u, URI v) throws URISyntaxException { testCount++; if (!u.equals(v)) throw new RuntimeException("Not equal: " + u + " " + v); @@ -1352,7 +1353,7 @@ public class Test { + " [" + Integer.toHexString(uh) + "]"); } - static void cmp0(Comparable u, Comparable v, boolean same) + static void cmp0(URI u, URI v, boolean same) throws URISyntaxException { int c = u.compareTo(v); @@ -1361,18 +1362,18 @@ public class Test { + " " + c); } - static void eq(Comparable u, Comparable v) throws URISyntaxException { + static void eq(URI u, URI v) throws URISyntaxException { eq0(u, v); cmp0(u, v, true); } - static void eqeq(Comparable u, Comparable v) { + static void eqeq(URI u, URI v) { testCount++; if (u != v) throw new RuntimeException("Not ==: " + u + " " + v); } - static void ne0(Comparable u, Comparable v) throws URISyntaxException { + static void ne0(URI u, URI v) throws URISyntaxException { testCount++; if (u.equals(v)) throw new RuntimeException("Equal: " + u + " " + v); @@ -1383,17 +1384,17 @@ public class Test { + "]"); } - static void ne(Comparable u, Comparable v) throws URISyntaxException { + static void ne(URI u, URI v) throws URISyntaxException { ne0(u, v); cmp0(u, v, false); } - static void lt(Comparable u, Comparable v) throws URISyntaxException { + static void lt(URI u, URI v) throws URISyntaxException { ne0(u, v); int c = u.compareTo(v); if (c >= 0) { - show((URI)u); - show((URI)v); + show(u); + show(v); throw new RuntimeException("Not less than: " + u + " " + v + " " + c); } @@ -1404,7 +1405,7 @@ public class Test { lt(new URI(s), new URI(t)); } - static void gt(Comparable u, Comparable v) throws URISyntaxException { + static void gt(URI u, URI v) throws URISyntaxException { lt(v, u); } @@ -1430,6 +1431,8 @@ public class Test { lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#g")); eq(new URI("http://host/a%00bcd"), new URI("http://host/a%00bcd")); ne(new URI("http://host/a%00bcd"), new URI("http://host/aZ00bcd")); + eq0(new URI("http://host/abc%e2def%C3ghi"), + new URI("http://host/abc%E2def%c3ghi")); lt("p", "s:p"); lt("s:p", "T:p"); @@ -1465,7 +1468,7 @@ public class Test { ObjectInputStream oi = new ObjectInputStream(bi); try { Object o = oi.readObject(); - eq(u, (Comparable)o); + eq(u, (URI)o); } catch (ClassNotFoundException x) { x.printStackTrace(); throw new RuntimeException(x.toString()); diff --git a/jdk/test/java/net/URL/B5086147.sh b/jdk/test/java/net/URL/B5086147.sh index e5830b9ecce..a669e1347ee 100644 --- a/jdk/test/java/net/URL/B5086147.sh +++ b/jdk/test/java/net/URL/B5086147.sh @@ -42,7 +42,7 @@ case "$OS" in exit 1; ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}B5086147.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}B5086147.java failures=0 diff --git a/jdk/test/java/net/URL/runconstructor.sh b/jdk/test/java/net/URL/runconstructor.sh index 5a8f09073d9..f64fd8509d1 100644 --- a/jdk/test/java/net/URL/runconstructor.sh +++ b/jdk/test/java/net/URL/runconstructor.sh @@ -44,7 +44,8 @@ case "$OS" in exit 1; ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}Constructor.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}${FS}Constructor.java failures=0 diff --git a/jdk/test/java/net/URLClassLoader/B5077773.sh b/jdk/test/java/net/URLClassLoader/B5077773.sh index 725829e58e5..9bd9a1e6f34 100644 --- a/jdk/test/java/net/URLClassLoader/B5077773.sh +++ b/jdk/test/java/net/URLClassLoader/B5077773.sh @@ -58,7 +58,8 @@ esac cp ${TESTSRC}${FS}foo.jar . -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}B5077773.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}${FS}B5077773.java WD=`pwd` ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} B5077773 diff --git a/jdk/test/java/net/URLClassLoader/closetest/build.sh b/jdk/test/java/net/URLClassLoader/closetest/build.sh index 0adb2e9efb1..651c8a45d6e 100644 --- a/jdk/test/java/net/URLClassLoader/closetest/build.sh +++ b/jdk/test/java/net/URLClassLoader/closetest/build.sh @@ -40,14 +40,19 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTCLASSES}" = "" ] then echo "TESTCLASSES not set. Test cannot execute. Failed." exit 1 fi -JAVAC="${TESTJAVA}/bin/javac" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac" +JAR="${COMPILEJAVA}/bin/jar" rm -rf ${TESTCLASSES}/test1 rm -rf ${TESTCLASSES}/test2 @@ -59,15 +64,15 @@ mkdir -p ${TESTCLASSES}/serverRoot cd ${TESTSRC}/test1/com/foo cp * ${TESTCLASSES}/test1/com/foo cd ${TESTCLASSES}/test1 -${JAVAC} com/foo/*.java -${JAR} cvf ../test1.jar com/foo/*.class com/foo/Resource* +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} com/foo/*.java +${JAR} ${TESTTOOLVMOPTS} cvf ../test1.jar com/foo/*.class com/foo/Resource* cd ${TESTSRC}/test2/com/foo cp * ${TESTCLASSES}/test2/com/foo cd ${TESTCLASSES}/test2 -${JAVAC} com/foo/*.java -${JAR} cvf ../test2.jar com/foo/*.class com/foo/Resource* +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} com/foo/*.java +${JAR} ${TESTTOOLVMOPTS} cvf ../test2.jar com/foo/*.class com/foo/Resource* cp ${TESTSRC}/serverRoot/Test.java ${TESTCLASSES}/serverRoot cd ${TESTCLASSES}/serverRoot -${JAVAC} Test.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} Test.java diff --git a/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh b/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh index 1654f314f88..976b8e8d00c 100644 --- a/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh +++ b/jdk/test/java/net/URLClassLoader/getresourceasstream/test.sh @@ -43,7 +43,7 @@ checkExit () { fi } -${TESTJAVA}/bin/javac -d . ${TESTSRC}/Test.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/Test.java cp ${TESTSRC}/test.jar . ${TESTJAVA}/bin/java ${TESTVMOPTS} Test diff --git a/jdk/test/java/net/URLClassLoader/sealing/checksealed.sh b/jdk/test/java/net/URLClassLoader/sealing/checksealed.sh index b675eb2f1a2..0d212c62aae 100644 --- a/jdk/test/java/net/URLClassLoader/sealing/checksealed.sh +++ b/jdk/test/java/net/URLClassLoader/sealing/checksealed.sh @@ -51,11 +51,13 @@ esac if [ x"$TESTJAVA" = x ]; then TESTJAVA=$1; fi +if [ x"$COMPILEJAVA" = x ]; then COMPILEJAVA=$1; fi if [ x"$TESTSRC" = x ]; then TESTSRC=.; fi CLASSPATH=".${PS}${TESTSRC}${FS}a${PS}${TESTSRC}${FS}b.jar" -${TESTJAVA}${FS}bin${FS}javac -classpath "${CLASSPATH}" -d . ${TESTSRC}${FS}CheckSealed.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath "${CLASSPATH}" -d . \ + ${TESTSRC}${FS}CheckSealed.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp "${CLASSPATH}" CheckSealed 1 if [ $? != 0 ]; then exit 1; fi ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp "${CLASSPATH}" CheckSealed 2 diff --git a/jdk/test/java/net/URLConnection/6212146/test.sh b/jdk/test/java/net/URLConnection/6212146/test.sh index 22c6473c77e..45f5310005e 100644 --- a/jdk/test/java/net/URLConnection/6212146/test.sh +++ b/jdk/test/java/net/URLConnection/6212146/test.sh @@ -63,7 +63,7 @@ mkdir jars cp ${TESTSRC}${FS}test.jar jars -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}Test.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}Test.java WD=`pwd` ulimit -H -n 300 diff --git a/jdk/test/java/net/URLConnection/UNCTest.sh b/jdk/test/java/net/URLConnection/UNCTest.sh index aa9f1842613..8030deb30e3 100644 --- a/jdk/test/java/net/URLConnection/UNCTest.sh +++ b/jdk/test/java/net/URLConnection/UNCTest.sh @@ -35,7 +35,7 @@ UNC="file://jdk/LOCAL-JAVA/jdk1.4/win/README.txt" OS=`uname -s` case "$OS" in Windows_95 | Windows_98 | Windows_NT ) - ${TESTJAVA}/bin/javac -d . ${TESTSRC}\\UNCTest.java + ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}\\UNCTest.java ${TESTJAVA}/bin/java ${TESTVMOPTS} UNCTest ${UNC} exit ;; diff --git a/jdk/test/java/net/ipv6tests/B6521014.java b/jdk/test/java/net/ipv6tests/B6521014.java index 3cb16b8dfe1..6bfe0b18a77 100644 --- a/jdk/test/java/net/ipv6tests/B6521014.java +++ b/jdk/test/java/net/ipv6tests/B6521014.java @@ -95,14 +95,12 @@ public class B6521014 { Socket sock; ServerSocket ssock; int port; - int localport; ssock = new ServerSocket(0); ssock.setSoTimeout(100); port = ssock.getLocalPort(); - localport = port + 1; sock = new Socket(); - sock.bind(new InetSocketAddress(sin, localport)); + sock.bind(new InetSocketAddress(sin, 0)); try { sock.connect(new InetSocketAddress(sin, port), 100); } catch (SocketTimeoutException e) { diff --git a/jdk/test/java/nio/charset/spi/basic.sh b/jdk/test/java/nio/charset/spi/basic.sh index e4f89c5823c..6b5ad3108ac 100644 --- a/jdk/test/java/nio/charset/spi/basic.sh +++ b/jdk/test/java/nio/charset/spi/basic.sh @@ -38,12 +38,13 @@ if [ -z "$TESTJAVA" ]; then if [ $# -lt 1 ]; then exit 1; fi TESTJAVA=$1; shift + COMPILEJDK="${TESTJAVA}" TESTSRC=`pwd` TESTCLASSES=`pwd` fi JAVA=$TESTJAVA/bin/java -JAR=$TESTJAVA/bin/jar +JAR=$COMPILEJAVA/bin/jar DIR=`pwd` case `uname` in @@ -72,7 +73,7 @@ if [ \! -d $EXTD ]; then cp $TESTCLASSES/FooProvider.class $TESTCLASSES/FooCharset.class $JARD mkdir $TESTD cp $TESTCLASSES/Test.class $TESTD - (cd $JARD; $JAR -cf $EXTD/test.jar *) + (cd $JARD; $JAR ${TESTTOOLVMOPTS} -cf $EXTD/test.jar *) fi if [ $# -gt 0 ]; then diff --git a/jdk/test/java/nio/file/Files/Misc.java b/jdk/test/java/nio/file/Files/Misc.java index 785dbefa1d1..6e704ee4489 100644 --- a/jdk/test/java/nio/file/Files/Misc.java +++ b/jdk/test/java/nio/file/Files/Misc.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 + * @bug 4313887 6838333 8005566 * @summary Unit test for miscellenous methods in java.nio.file.Files * @library .. */ diff --git a/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java index dd005c2c326..40792dfde46 100644 --- a/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java +++ b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java @@ -49,9 +49,9 @@ public class Basic { check(!attrs.isSymbolicLink(), "is not a link"); check(!attrs.isOther(), "is not other"); - // last-modified-time should match java.io.File + // last-modified-time should match java.io.File in seconds File f = new File(dir.toString()); - check(f.lastModified() == attrs.lastModifiedTime().toMillis(), + check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS), "last-modified time should be the same"); } @@ -64,10 +64,10 @@ public class Basic { check(!attrs.isSymbolicLink(), "is not a link"); check(!attrs.isOther(), "is not other"); - // size and last-modified-time should match java.io.File + // size and last-modified-time should match java.io.File in seconds File f = new File(file.toString()); check(f.length() == attrs.size(), "size should be the same"); - check(f.lastModified() == attrs.lastModifiedTime().toMillis(), + check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS), "last-modified time should be the same"); // copy last-modified time and file create time from directory to file, diff --git a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh index 4f758b410c4..9c7a2eac4ec 100644 --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh @@ -49,7 +49,7 @@ mkdir -p classes for dir in `echo ${TESTCLASSPATH:-$TESTCLASSES} | sed -e "s/$PS/ /"` ; do cp $dir/*.class classes ; done rm classes/ExtLoadedImpl.class classes/ExtLoadedImpl_Stub.class classes/CheckLoader.class mkdir -p ext -$TESTJAVA/bin/jar cf ext/ext.jar -C $TESTCLASSES ExtLoadedImpl.class -C $TESTCLASSES ExtLoadedImpl_Stub.class -C $TESTCLASSES CheckLoader.class +$COMPILEJAVA/bin/jar ${TESTTOOLVMOPTS} cf ext/ext.jar -C $TESTCLASSES ExtLoadedImpl.class -C $TESTCLASSES ExtLoadedImpl_Stub.class -C $TESTCLASSES CheckLoader.class $TESTJAVA/bin/java ${TESTVMOPTS} -cp classes -Dtest.src=$TESTSRC -Dtest.classes=$TESTCLASSES -Djava.security.policy=$TESTSRC/security.policy -Djava.ext.dirs=ext ExtLoadedImplTest diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/ActivateMe.java b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/ActivateMe.java index 9700c997107..c0230a97226 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/ActivateMe.java +++ b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/ActivateMe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -28,7 +28,5 @@ import java.rmi.Remote; import java.rmi.RemoteException; interface ActivateMe extends Remote { public void ping() throws RemoteException; - public void unregister() throws Exception; public void shutdown() throws Exception; - public void justGoAway() throws RemoteException; } diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/Callback_Stub.java b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/Callback_Stub.java deleted file mode 100644 index ecf0190e922..00000000000 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/Callback_Stub.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2000, 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. - * - * 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. - */ - -// Stub class generated by rmic, do not edit. -// Contents subject to change without notice. - -public final class Callback_Stub - extends java.rmi.server.RemoteStub - implements CallbackInterface, java.rmi.Remote -{ - private static final java.rmi.server.Operation[] operations = { - new java.rmi.server.Operation("int getNumDeactivated()"), - new java.rmi.server.Operation("void inc()") - }; - - private static final long interfaceHash = -1008194523112388035L; - - private static final long serialVersionUID = 2; - - private static boolean useNewInvoke; - private static java.lang.reflect.Method $method_getNumDeactivated_0; - private static java.lang.reflect.Method $method_inc_1; - - static { - try { - java.rmi.server.RemoteRef.class.getMethod("invoke", - new java.lang.Class[] { - java.rmi.Remote.class, - java.lang.reflect.Method.class, - java.lang.Object[].class, - long.class - }); - useNewInvoke = true; - $method_getNumDeactivated_0 = CallbackInterface.class.getMethod("getNumDeactivated", new java.lang.Class[] {}); - $method_inc_1 = CallbackInterface.class.getMethod("inc", new java.lang.Class[] {}); - } catch (java.lang.NoSuchMethodException e) { - useNewInvoke = false; - } - } - - // constructors - public Callback_Stub() { - super(); - } - public Callback_Stub(java.rmi.server.RemoteRef ref) { - super(ref); - } - - // methods from remote interfaces - - // implementation of getNumDeactivated() - public int getNumDeactivated() - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - Object $result = ref.invoke(this, $method_getNumDeactivated_0, null, -761062487639949912L); - return ((java.lang.Integer) $result).intValue(); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); - ref.invoke(call); - int $result; - try { - java.io.ObjectInput in = call.getInputStream(); - $result = in.readInt(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling return", e); - } finally { - ref.done(call); - } - return $result; - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } - - // implementation of inc() - public void inc() - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - ref.invoke(this, $method_inc_1, null, 4394985085384332959L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); - ref.invoke(call); - ref.done(call); - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } -} diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java index 59fee9da723..bc5976b74fe 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java +++ b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -28,42 +28,22 @@ * @author Ann Wollrath * * @library ../../../testlibrary - * @build TestLibrary RMID ActivationLibrary - * ActivateMe CallbackInterface UnregisterGroup_Stub Callback_Stub - * @run main/othervm/policy=security.policy/timeout=480 UnregisterGroup + * @build TestLibrary RMID ActivationLibrary ActivateMe + * @run main/othervm/policy=security.policy UnregisterGroup */ import java.io.*; import java.rmi.*; import java.rmi.activation.*; import java.rmi.server.*; -import java.rmi.registry.*; import java.util.Properties; -class Callback extends UnicastRemoteObject implements CallbackInterface { - public int num_deactivated = 0; - - public Callback() throws RemoteException { super(); } - - public synchronized void inc() throws RemoteException { - num_deactivated++; - } - - public synchronized int getNumDeactivated() throws RemoteException { - return num_deactivated; - } -} - -public class UnregisterGroup - extends Activatable - implements ActivateMe, Runnable +public class UnregisterGroup extends Activatable implements ActivateMe { - private static Exception exception = null; - private static String error = null; - private static boolean done = false; - private static ActivateMe lastResortExitObj = null; + private static volatile Exception exception = null; + private static volatile String error = null; + private static volatile boolean done = false; private static final int NUM_OBJECTS = 10; - private static int registryPort = -1; public UnregisterGroup(ActivationID id, MarshalledObject mobj) throws Exception @@ -71,69 +51,25 @@ public class UnregisterGroup super(id, 0); } - public void ping() - {} - - public void unregister() throws Exception { - super.unregister(super.getID()); - } + /** + * Does nothing, but serves to activate this object. + */ + public void ping() { } /** - * Spawns a thread to deactivate the object. + * Deactivates the object. We need to unexport forcibly because + * this call is in-progress on this object, which is the same object + * that we are trying to deactivate. */ public void shutdown() throws Exception { - (new Thread(this,"UnregisterGroup")).start(); - } - - /** - * To support exiting of group VM as a last resort - */ - public void justGoAway() { - System.exit(0); - } - - /** - * Thread to deactivate object. Get the callback object from the registry, - * call inc() on it, and finally call deactivate(). The call to - * deactivate() causes this JVM to be destroyed, so anything following - * might not be executed. - */ - public void run() { - String regPortStr = System.getProperty("unregisterGroup.port"); - int regPort = -1; - - if (regPortStr != null) { - regPort = Integer.parseInt(regPortStr); - } - - try { - CallbackInterface cobj = - (CallbackInterface)Naming.lookup("//:" + regPort + "/Callback"); - cobj.inc(); - System.err.println("cobj.inc called and returned ok"); - } catch (Exception e) { - System.err.println("cobj.inc exception"); - e.printStackTrace(); - } - + Activatable.unexportObject(this, true); ActivationLibrary.deactivate(this, getID()); - System.err.println("\tActivationLibrary.deactivate returned"); } public static void main(String[] args) throws RemoteException { - System.err.println("\nRegression test for bug 4134233\n"); TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager"); RMID rmid = null; - // Create registry and export callback object so they're - // available to the objects that are activated below. - // TODO: see if we can use RMID's registry instead of - // creating one here. - Registry registry = TestLibrary.createRegistryOnUnusedPort(); - registryPort = TestLibrary.getRegistryPort(registry); - Callback robj = new Callback(); - registry.rebind("Callback", robj); - try { RMID.removeLog(); rmid = RMID.createRMID(); @@ -145,11 +81,8 @@ public class UnregisterGroup final Properties p = new Properties(); // this test must always set policies/managers in its // activation groups - p.put("java.security.policy", - TestParams.defaultGroupPolicy); - p.put("java.security.manager", - TestParams.defaultSecurityManager); - p.put("unregisterGroup.port", Integer.toString(registryPort)); + p.put("java.security.policy", TestParams.defaultGroupPolicy); + p.put("java.security.manager", TestParams.defaultSecurityManager); Thread t = new Thread() { public void run () { @@ -173,7 +106,6 @@ public class UnregisterGroup System.err.println("Activating object: " + i); obj[i].ping(); } - lastResortExitObj = obj[0]; System.err.println("Unregistering group"); system.unregisterGroup(groupID); @@ -187,7 +119,6 @@ public class UnregisterGroup "group unregistered"); } - /* * Deactivate objects so group VM will exit. */ @@ -196,7 +127,7 @@ public class UnregisterGroup obj[i].shutdown(); obj[i] = null; } - lastResortExitObj = null; + System.err.println("Successfully deactivated all objects."); } catch (Exception e) { exception = e; @@ -207,7 +138,11 @@ public class UnregisterGroup }; t.start(); - t.join(120000); + + // Default jtreg timeout is two minutes. + // Timeout ourselves after one minute so that + // we can clean up. + t.join(60000); if (exception != null) { TestLibrary.bomb("test failed", exception); @@ -221,31 +156,6 @@ public class UnregisterGroup } catch (Exception e) { TestLibrary.bomb("test failed", e); } finally { - if (lastResortExitObj != null) { - try { - lastResortExitObj.justGoAway(); - } catch (Exception munch) { - } - } - - // Wait for the object deactivation to take place first - try { - //get the callback object - int maxwait=30; - int nd = robj.getNumDeactivated(); - while ((nd < NUM_OBJECTS) && (maxwait> 0)) { - System.err.println("num_deactivated="+nd); - try { - Thread.sleep(1000); - } catch (InterruptedException ie) {} - maxwait--; - nd = robj.getNumDeactivated(); - } - } catch (Exception ce) { - System.err.println("E:"+ce); - ce.printStackTrace(); - } - ActivationLibrary.rmidCleanup(rmid); } } diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup_Stub.java b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup_Stub.java deleted file mode 100644 index 4bd96719855..00000000000 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup_Stub.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 1998, 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. - * - * 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. - */ - -// Stub class generated by rmic, do not edit. -// Contents subject to change without notice. - -public final class UnregisterGroup_Stub - extends java.rmi.server.RemoteStub - implements ActivateMe, java.rmi.Remote -{ - private static final java.rmi.server.Operation[] operations = { - new java.rmi.server.Operation("void justGoAway()"), - new java.rmi.server.Operation("void ping()"), - new java.rmi.server.Operation("void shutdown()"), - new java.rmi.server.Operation("void unregister()") - }; - - private static final long interfaceHash = -4733924075192691630L; - - private static final long serialVersionUID = 2; - - private static boolean useNewInvoke; - private static java.lang.reflect.Method $method_justGoAway_0; - private static java.lang.reflect.Method $method_ping_1; - private static java.lang.reflect.Method $method_shutdown_2; - private static java.lang.reflect.Method $method_unregister_3; - - static { - try { - java.rmi.server.RemoteRef.class.getMethod("invoke", - new java.lang.Class[] { - java.rmi.Remote.class, - java.lang.reflect.Method.class, - java.lang.Object[].class, - long.class - }); - useNewInvoke = true; - $method_justGoAway_0 = ActivateMe.class.getMethod("justGoAway", new java.lang.Class[] {}); - $method_ping_1 = ActivateMe.class.getMethod("ping", new java.lang.Class[] {}); - $method_shutdown_2 = ActivateMe.class.getMethod("shutdown", new java.lang.Class[] {}); - $method_unregister_3 = ActivateMe.class.getMethod("unregister", new java.lang.Class[] {}); - } catch (java.lang.NoSuchMethodException e) { - useNewInvoke = false; - } - } - - // constructors - public UnregisterGroup_Stub() { - super(); - } - public UnregisterGroup_Stub(java.rmi.server.RemoteRef ref) { - super(ref); - } - - // methods from remote interfaces - - // implementation of justGoAway() - public void justGoAway() - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - ref.invoke(this, $method_justGoAway_0, null, -5382478058620783904L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); - ref.invoke(call); - ref.done(call); - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } - - // implementation of ping() - public void ping() - throws java.rmi.RemoteException - { - try { - if (useNewInvoke) { - ref.invoke(this, $method_ping_1, null, 5866401369815527589L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); - ref.invoke(call); - ref.done(call); - } - } catch (java.lang.RuntimeException e) { - throw e; - } catch (java.rmi.RemoteException e) { - throw e; - } catch (java.lang.Exception e) { - throw new java.rmi.UnexpectedException("undeclared checked exception", e); - } - } - - // implementation of shutdown() - public void shutdown() - throws java.lang.Exception - { - if (useNewInvoke) { - ref.invoke(this, $method_shutdown_2, null, -7207851917985848402L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash); - ref.invoke(call); - ref.done(call); - } - } - - // implementation of unregister() - public void unregister() - throws java.lang.Exception - { - if (useNewInvoke) { - ref.invoke(this, $method_unregister_3, null, -5366864281862648102L); - } else { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash); - ref.invoke(call); - ref.done(call); - } - } -} diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy index fa1bc1e9f83..0e43c5d37ab 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy +++ b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy @@ -1,5 +1,4 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; - permission com.sun.rmi.rmid.ExecOptionPermission "-DunregisterGroup.port=*"; }; diff --git a/jdk/test/java/rmi/registry/readTest/readTest.sh b/jdk/test/java/rmi/registry/readTest/readTest.sh index 5fda0a5a314..dad6847f304 100644 --- a/jdk/test/java/rmi/registry/readTest/readTest.sh +++ b/jdk/test/java/rmi/registry/readTest/readTest.sh @@ -53,15 +53,15 @@ esac TEST_CLASSPATH=.$PS${TESTCLASSPATH:-$TESTCLASSES} cp -r ${TESTSRC}${FS}* . -${TESTJAVA}${FS}bin${FS}javac testPkg${FS}*java -${TESTJAVA}${FS}bin${FS}javac -cp $TEST_CLASSPATH readTest.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} testPkg${FS}*java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp $TEST_CLASSPATH readTest.java mkdir rmi_tmp RMIREG_OUT=rmi.out #start rmiregistry without any local classes on classpath cd rmi_tmp # NOTE: This RMI Registry port must match TestLibrary.READTEST_REGISTRY_PORT -${TESTJAVA}${FS}bin${FS}rmiregistry 64005 > ..${FS}${RMIREG_OUT} 2>&1 & +${TESTJAVA}${FS}bin${FS}rmiregistry ${TESTTOOLVMOPTS} 64005 > ..${FS}${RMIREG_OUT} 2>&1 & RMIREG_PID=$! # allow some time to start sleep 3 diff --git a/jdk/test/java/rmi/testlibrary/TestLibrary.java b/jdk/test/java/rmi/testlibrary/TestLibrary.java index 07ed308355c..10b84c639b1 100644 --- a/jdk/test/java/rmi/testlibrary/TestLibrary.java +++ b/jdk/test/java/rmi/testlibrary/TestLibrary.java @@ -93,7 +93,7 @@ public class TestLibrary { public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 64003; public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 64004; public final static int READTEST_REGISTRY_PORT = 64005; - private final static int MAX_SERVER_SOCKET_TRIES = 10; + private final static int MAX_SERVER_SOCKET_TRIES = 2*(FIXED_PORT_MAX-FIXED_PORT_MIN+1); static void mesg(Object mesg) { System.err.println("TEST_LIBRARY: " + mesg.toString()); diff --git a/jdk/test/java/security/KeyStore/PBETest.java b/jdk/test/java/security/KeyStore/PBETest.java new file mode 100644 index 00000000000..be437d03bbd --- /dev/null +++ b/jdk/test/java/security/KeyStore/PBETest.java @@ -0,0 +1,103 @@ +/* + * 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 8006591 + * @summary Protect keystore entries using stronger PBE algorithms + */ + +import java.io.*; +import java.security.*; +import javax.crypto.spec.*; + +// Retrieve a keystore entry, protected by the default encryption algorithm. +// Set the keystore entry, protected by a stronger encryption algorithm. + +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 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 = { + 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20 + }; + private static final byte[] SALT = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + private static final int ITERATION_COUNT = 1024; + + public static void main(String[] args) throws Exception { + + new File(NEW_KEYSTORE).delete(); + + try { + KeyStore keystore = load(KEYSTORE_TYPE, KEYSTORE, PASSWORD); + KeyStore.Entry entry = + keystore.getEntry(ALIAS, + new KeyStore.PasswordProtection(PASSWORD)); + System.out.println("Retrieved entry named '" + ALIAS + "'"); + + // 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); + + System.out.println("Storing keystore to: " + NEW_KEYSTORE); + keystore2.store(new FileOutputStream(NEW_KEYSTORE), PASSWORD); + + keystore2 = load(NEW_KEYSTORE_TYPE, NEW_KEYSTORE, PASSWORD); + entry = keystore2.getEntry(ALIAS, + new KeyStore.PasswordProtection(PASSWORD)); + System.out.println("Retrieved entry named '" + ALIAS + "'"); + + } finally { + new File(NEW_KEYSTORE).delete(); + System.out.println("Deleted keystore: " + NEW_KEYSTORE); + } + } + + private static KeyStore load(String type, String path, char[] password) + throws Exception { + + FileInputStream stream = null; + if (path != null) { + stream = new FileInputStream(path); + } + KeyStore keystore = KeyStore.getInstance(type); + System.out.println("Loading keystore from: " + path); + keystore.load(stream, password); + + return keystore; + } +} diff --git a/jdk/test/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh b/jdk/test/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh index a62cba4ec3a..7f5dc78c23a 100644 --- a/jdk/test/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh +++ b/jdk/test/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh @@ -43,6 +43,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -78,11 +82,11 @@ if [ ! -d provider ] ; then fi # compile the test program -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES}${FILESEP} \ ${TESTSRC}${FILESEP}ClassLoaderDeadlock.java -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES}${FILESEP}provider${FILESEP} \ ${TESTSRC}${FILESEP}provider${FILESEP}HashProvider.java diff --git a/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh index acf8ff21033..e817db37898 100644 --- a/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh +++ b/jdk/test/java/security/Security/ClassLoaderDeadlock/Deadlock2.sh @@ -47,6 +47,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -88,12 +92,12 @@ else fi # compile and package the test program -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES} \ ${TESTSRC}${FILESEP}CreateSerialized.java \ ${TESTSRC}${FILESEP}Deadlock2.java -${TESTJAVA}${FILESEP}bin${FILESEP}jar \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}jar ${TESTTOOLVMOPTS} \ -cvf testlib${FILESEP}Deadlock2.jar \ Deadlock2*.class diff --git a/jdk/test/java/security/Security/signedfirst/Dyn.sh b/jdk/test/java/security/Security/signedfirst/Dyn.sh index 64d0dd3f775..73cff3e80da 100644 --- a/jdk/test/java/security/Security/signedfirst/Dyn.sh +++ b/jdk/test/java/security/Security/signedfirst/Dyn.sh @@ -43,6 +43,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -77,7 +81,7 @@ cd ${TESTCLASSES}${FILESEP} rm DynSignedProvFirst.class # compile the test program -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FILESEP}exp.jar \ -d ${TESTCLASSES}${FILESEP} \ ${TESTSRC}${FILESEP}DynSignedProvFirst.java diff --git a/jdk/test/java/security/Security/signedfirst/Static.sh b/jdk/test/java/security/Security/signedfirst/Static.sh index 544a3b1a3ff..46765e4a92b 100644 --- a/jdk/test/java/security/Security/signedfirst/Static.sh +++ b/jdk/test/java/security/Security/signedfirst/Static.sh @@ -43,6 +43,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -77,7 +81,7 @@ cd ${TESTCLASSES}${FILESEP} rm StaticSignedProvFirst.class # compile the test program -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath "${TESTCLASSES}${PATHSEP}${TESTSRC}${FILESEP}exp.jar" \ -d ${TESTCLASSES}${FILESEP} \ ${TESTSRC}${FILESEP}StaticSignedProvFirst.java diff --git a/jdk/test/java/security/cert/CertificateFactory/slowstream.sh b/jdk/test/java/security/cert/CertificateFactory/slowstream.sh index 72d3fcf6c8c..40526970602 100644 --- a/jdk/test/java/security/cert/CertificateFactory/slowstream.sh +++ b/jdk/test/java/security/cert/CertificateFactory/slowstream.sh @@ -33,6 +33,9 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi # set platform-dependent variables OS=`uname -s` @@ -45,6 +48,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}SlowStream.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}${FS}SlowStream.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dtest.src=${TESTSRC} SlowStreamWriter | \ ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} SlowStreamReader diff --git a/jdk/test/java/text/Format/DecimalFormat/TieRoundingTest.java b/jdk/test/java/text/Format/DecimalFormat/TieRoundingTest.java new file mode 100644 index 00000000000..fb460db2e1f --- /dev/null +++ b/jdk/test/java/text/Format/DecimalFormat/TieRoundingTest.java @@ -0,0 +1,411 @@ +/* + * 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 7131459 + * @summary test various situations of NumberFormat rounding when close to tie + * @author Olivier Lagneau + * @run main TieRoundingTest + * + */ + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.NumberFormat; +import java.text.DecimalFormat; +import java.math.RoundingMode; +import java.util.Locale; + +public class TieRoundingTest { + + static int testCounter = 0; + static int errorCounter = 0; + static boolean allPassed = true; + + static void formatOutputTestDouble(NumberFormat nf, + double doubleToTest, + String tiePosition, + String inputDigits, + String expectedOutput) { + + int mfd = nf.getMaximumFractionDigits(); + RoundingMode rm = nf.getRoundingMode(); + String result = nf.format(doubleToTest); + + if (!result.equals(expectedOutput)) { + System.out.println(); + System.out.println("========================================"); + System.out.println("***Error formatting double value from string : " + + inputDigits); + System.out.println("NumberFormat pattern is : " + + ((DecimalFormat ) nf).toPattern()); + System.out.println("Maximum number of fractional digits : " + mfd); + System.out.println("Fractional rounding digit : " + (mfd + 1)); + System.out.println("Position of value relative to tie : " + tiePosition); + System.out.println("Rounding Mode : " + rm); + System.out.println("BigDecimal output : " + + new BigDecimal(doubleToTest).toString()); + System.out.println("FloatingDecimal output : " + doubleToTest); + System.out.println( + "Error. Formatted result different from expected." + + "\nExpected output is : \"" + expectedOutput + "\"" + + "\nFormated output is : \"" + result + "\""); + System.out.println("========================================"); + System.out.println(); + + errorCounter++; + allPassed = false; + } else { + testCounter++; + System.out.println("\nSuccess for double value : " + doubleToTest + " :"); + System.out.println(" Input digits :" + inputDigits + + ", BigDecimal value : " + + new BigDecimal(doubleToTest).toString()); + System.out.print(" Rounding mode: " + rm); + System.out.print(", fract digits : " + mfd); + System.out.print(", position : " + tiePosition + " tie"); + System.out.print(", result : " + result); + System.out.println(", expected : " + expectedOutput); + } + } + + static void formatOutputTestLong(NumberFormat nf, + long longToTest, + String tiePosition, + String inputDigits, + String expectedOutput) { + + int mfd = nf.getMaximumFractionDigits(); + RoundingMode rm = nf.getRoundingMode(); + String result = nf.format(longToTest); + + if (!result.equals(expectedOutput)) { + System.out.println(); + System.out.println("========================================"); + System.out.println("***Error formatting double value from string : " + + inputDigits); + System.out.println("NumberFormat pattern is : " + + ((DecimalFormat ) nf).toPattern()); + System.out.println("Maximum number of fractional digits : " + mfd); + System.out.println("Fractional rounding digit : " + (mfd + 1)); + System.out.println("Position of value relative to tie : " + tiePosition); + System.out.println("Rounding Mode : " + rm); + System.out.println( + "Error. Formatted result different from expected." + + "\nExpected output is : \"" + expectedOutput + "\"" + + "\nFormated output is : \"" + result + "\""); + System.out.println("========================================"); + System.out.println(); + + errorCounter++; + allPassed = false; + } else { + testCounter++; + System.out.print("Success. Long input :" + inputDigits); + System.out.print(", rounding : " + rm); + System.out.print(", fract digits : " + mfd); + System.out.print(", tie position : " + tiePosition); + System.out.println(", expected : " + expectedOutput); + + } + } + + static void formatOutputTestObject(NumberFormat nf, + Object someNumber, + String tiePosition, + String inputDigits, + String expectedOutput) { + + int mfd = nf.getMaximumFractionDigits(); + RoundingMode rm = nf.getRoundingMode(); + String result = nf.format(someNumber); + + if (!result.equals(expectedOutput)) { + System.out.println(); + System.out.println("========================================"); + System.out.println("***Error formatting number value from string : " + + inputDigits); + System.out.println("NumberFormat pattern is : " + + ((DecimalFormat ) nf).toPattern()); + System.out.println("Maximum number of fractional digits : " + mfd); + System.out.println("Fractional rounding digit : " + (mfd + 1)); + System.out.println("Position of value relative to tie : " + tiePosition); + System.out.println("Rounding Mode : " + rm); + System.out.println("Number self output representation: " + someNumber); + System.out.println( + "Error. Formatted result different from expected." + + "\nExpected output is : \"" + expectedOutput + "\"" + + "\nFormated output is : \"" + result + "\""); + System.out.println("========================================"); + System.out.println(); + + errorCounter++; + allPassed = false; + } else { + testCounter++; + System.out.print("Success. Number input :" + inputDigits); + System.out.print(", rounding : " + rm); + System.out.print(", fract digits : " + mfd); + System.out.print(", tie position : " + tiePosition); + System.out.println(", expected : " + expectedOutput); + } + } + + public static void main(String[] args) { + + // Only the 3 rounding modes below may be impacted by bug 7131459. + // So we do not test the other rounding modes. + RoundingMode[] roundingModes = { + RoundingMode.HALF_DOWN, + RoundingMode.HALF_EVEN, + RoundingMode.HALF_UP + }; + + // Precise the relative position of input value against its closest tie. + String[] tieRelativePositions = { + "below", "exact", "above", + "below", "exact", "above", + "below", "exact", "above", + "below", "exact", "above" + }; + + // =============== Testing double (and thus float) value cases ========= + + System.out.println("\n===== testing 3 digits rounding position ====="); + double[] values3FractDigits = { + // unimpacting values close to tie, with less than 3 input fract digits + 1.115d, 1.125d, 1.135d, + // impacting close to tie values covering all 6 cases + 0.3115d, 0.3125d, 0.3135d, + 0.6865d, 0.6875d, 0.6885d, + // unimpacting values close to tie, with more than 3 input fract digits + 1.46885d, 2.46875d, 1.46865d + }; + + String[] inputs3FractDigits = { + "1.115d", "1.125d", "1.135d", + "0.3115d", "0.3125d", "0.3135d", + "0.6865d", "0.6875d", "0.6885d", + "1.46885d", "2.46875d", "1.46865d" + }; + + String[][] expected3FractDigits = { + {"1.115", "1.125", "1.135", + "0.311", "0.312", "0.314", + "0.686", "0.687", "0.689", + "1.469", "2.469", "1.469" + }, + {"1.115", "1.125", "1.135", + "0.311", "0.312", "0.314", + "0.686", "0.688", "0.689", + "1.469", "2.469", "1.469" + }, + {"1.115", "1.125", "1.135", + "0.311", "0.313", "0.314", + "0.686", "0.688", "0.689", + "1.469", "2.469", "1.469" + }, + }; + + + for (int r = 0; r < roundingModes.length; r++) { + NumberFormat dfDefault = NumberFormat.getInstance(Locale.US); + RoundingMode rmode = roundingModes[r]; + dfDefault.setRoundingMode(rmode); + System.out.println("\n----- Now checking " + rmode + + " rounding mode -----"); + + for (int i = 0; i < values3FractDigits.length; i++) { + double d = values3FractDigits[i]; + String tiePosition = tieRelativePositions[i]; + String input = inputs3FractDigits[i]; + String expected = expected3FractDigits[r][i]; + + formatOutputTestDouble(dfDefault, d, tiePosition, input, expected); + } + } + + System.out.println("\n===== testing 5 digits rounding position ====="); + double[] values5FractDigits = { + // unimpacting values close to tie, with less than 5 input fract digits + 1.3135d, 1.3125d, 1.3115d, + // impacting values close to tie, covering all 6 cases + 1.328115d, 1.328125d, 1.328135d, + 1.796865d, 1.796875d, 1.796885d, + // unimpacting values close to tie, with more than 5 input fract digits + 1.3281149999999d, 1.75390625d, 1.7968750000001d + }; + + String[] inputs5FractDigits = { + "1.3135d", "1.3125d", "1.3115d", + "1.328115d", "1.328125d", "1.328135d", + "1.796865d", "1.796875d", "1.796885d", + "1.3281149999999d", "1.75390625d", "1.7968750000001d" + }; + + String[][] expected5FractDigits = { + {"1.3135", "1.3125", "1.3115", + "1.32811", "1.32812", "1.32814", + "1.79686", "1.79687", "1.79689", + "1.32811", "1.75391", "1.79688" + }, + {"1.3135", "1.3125", "1.3115", + "1.32811", "1.32812", "1.32814", + "1.79686", "1.79688", "1.79689", + "1.32811", "1.75391", "1.79688" + }, + {"1.3135", "1.3125", "1.3115", + "1.32811", "1.32813", "1.32814", + "1.79686", "1.79688", "1.79689", + "1.32811", "1.75391", "1.79688" + } + }; + + + for (int r = 0; r < roundingModes.length; r++) { + DecimalFormat df5 = (DecimalFormat) NumberFormat.getInstance(Locale.US); + RoundingMode rmode = roundingModes[r]; + df5.setRoundingMode(rmode); + System.out.println("\n----- Now checking " + rmode + + " rounding mode -----"); + df5.applyPattern("#,###.#####"); + + for (int i = 0; i < values5FractDigits.length; i++) { + double d = values5FractDigits[i]; + String tiePosition = tieRelativePositions[i]; + String input = inputs5FractDigits[i]; + String expected = expected5FractDigits[r][i]; + + formatOutputTestDouble(df5, d, tiePosition, input, expected); + } + } + + // ==================== Testing long value cases ==================== + + System.out.println("\n===== testing long values ====="); + long l = 123456789012345L; + DecimalFormat dfLong = (DecimalFormat) NumberFormat.getInstance(Locale.US); + String tiePosition = "exact"; + String input = "123456789012345L"; + String expected = "123,456,789,012,345"; + String result = dfLong.format(l); + formatOutputTestLong(dfLong, l, tiePosition, input, expected); + + dfLong.applyPattern("0.###E0"); + expected = "1.235E14"; + formatOutputTestLong(dfLong, l, tiePosition, input, expected); + + l = 123450000000000L; + input = "123450000000000L"; + expected = "1.234E14"; + formatOutputTestLong(dfLong, l, tiePosition, input, expected); + + l = 987750000000000L; + input = "987750000000000L"; + expected = "9.878E14"; + formatOutputTestLong(dfLong, l, tiePosition, input, expected); + + dfLong.applyPattern("#,###.0E0"); + l = 987755000000000L; + input = "987755000000000L"; + expected = "987.76E12"; + + formatOutputTestLong(dfLong, l, tiePosition, input, expected); + + + // ================= Testing BigInteger value cases ================= + + System.out.println("\n===== testing BigInteger values ====="); + String stringValue = "12345678901234567890123456789012345"; + BigInteger bi = new BigInteger(stringValue); + DecimalFormat dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US); + tiePosition = "exact"; + input = stringValue; + expected = "12,345,678,901,234,567,890,123,456,789,012,345"; + formatOutputTestObject(dfBig, bi, tiePosition, input, expected); + + dfBig.applyPattern("0.###E0"); + expected = "1.235E34"; + formatOutputTestObject(dfBig, bi, tiePosition, input, expected); + + stringValue = "12345000000000000000000000000000000"; + input = stringValue; + bi = new BigInteger(stringValue); + expected = "1.234E34"; + formatOutputTestObject(dfBig, bi, tiePosition, input, expected); + + stringValue = "12345000000000000000000000000000001"; + input = stringValue; + bi = new BigInteger(stringValue); + expected = "1.235E34"; + formatOutputTestObject(dfBig, bi, tiePosition, input, expected); + + stringValue = "98755000000000000000000000000000000"; + input = stringValue; + bi = new BigInteger(stringValue); + expected = "9.876E34"; + formatOutputTestObject(dfBig, bi, tiePosition, input, expected); + + dfLong.applyPattern("#,###.0E0"); + stringValue = "98775500000000000000000000000000000"; + input = stringValue; + expected = "987.76E34"; + + // =============== Testing BigDecimal value cases ================ + + System.out.println("\n===== testing BigDecimal values ====="); + dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US); + + stringValue = "0.68850000000000000088817841970012523233890533447265625"; + BigDecimal bd = new BigDecimal(stringValue); + tiePosition = "exact"; + input = stringValue; + expected = "0.689"; + formatOutputTestObject(dfBig, bd, tiePosition, input, expected); + + stringValue = "0.31149999999999999911182158029987476766109466552734375"; + bd = new BigDecimal(stringValue); + dfBig.applyPattern("#,##0.####"); + tiePosition = "exact"; + input = stringValue; + expected = "0.3115"; + formatOutputTestObject(dfBig, bd, tiePosition, input, expected); + + // ==================== Printing results and exiting =================== + + System.out.println(); + System.out.println("==> " + testCounter + " tests passed successfully"); + System.out.println("==> " + errorCounter + " tests failed"); + + System.out.println(); + if (allPassed) { + System.out.println( + "Success in formating all the values with the given parameters"); + } else { + String s = "Test failed with " + errorCounter + " formating error(s)."; + System.out.println(s); + throw new RuntimeException(s); + } + } +} 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 new file mode 100644 index 00000000000..918ad84d621 --- /dev/null +++ b/jdk/test/java/time/META-INF/services/java.time.temporal.Chrono @@ -0,0 +1 @@ +tck.java.time.calendar.CopticChrono diff --git a/jdk/test/java/time/TEST.properties b/jdk/test/java/time/TEST.properties new file mode 100644 index 00000000000..ccf8ed60635 --- /dev/null +++ b/jdk/test/java/time/TEST.properties @@ -0,0 +1,3 @@ +# Threeten test uses TestNG +TestNG.dirs = . + diff --git a/jdk/test/java/time/tck/java/time/AbstractDateTimeTest.java b/jdk/test/java/time/tck/java/time/AbstractDateTimeTest.java new file mode 100644 index 00000000000..d44d2410f28 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/AbstractDateTimeTest.java @@ -0,0 +1,278 @@ +/* + * 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) 2011-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 java.time.*; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.util.List; + +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalField; + +import org.testng.annotations.Test; +import test.java.time.AbstractTest; +import test.java.time.temporal.MockFieldNoValue; + +/** + * Base test class for {@code Temporal}. + */ +public abstract class AbstractDateTimeTest extends AbstractTCKTest { + + /** + * Sample {@code Temporal} objects. + * @return the objects, not null + */ + protected abstract List samples(); + + /** + * List of valid supported fields. + * @return the fields, not null + */ + protected abstract List validFields(); + + /** + * List of invalid unsupported fields. + * @return the fields, not null + */ + protected abstract List invalidFields(); + + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test(groups = "tck") + public void basicTest_isSupported_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + assertEquals(sample.isSupported(field), true, "Failed on " + sample + " " + field); + } + } + } + + @Test(groups = "tck") + public void basicTest_isSupported_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + assertEquals(sample.isSupported(field), false, "Failed on " + sample + " " + field); + } + } + } + + @Test(groups = "tck") + public void basicTest_isSupported_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + assertEquals(sample.isSupported(null), false, "Failed on " + sample); + } + } + + //----------------------------------------------------------------------- + // range(TemporalField) + //----------------------------------------------------------------------- + @Test(groups = "tck") + public void basicTest_range_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + sample.range(field); // no exception + } + } + } + + @Test(groups = "tck") + public void basicTest_range_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + try { + sample.range(field); + fail("Failed on " + sample + " " + field); + } catch (DateTimeException ex) { + // expected + } + } + } + } + + @Test(groups = "tck") + public void basicTest_range_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + try { + sample.range(null); + fail("Failed on " + sample); + } catch (NullPointerException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test(groups = "tck") + public void basicTest_get_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + if (sample.range(field).isIntValue()) { + sample.get(field); // no exception + } else { + try { + sample.get(field); + fail("Failed on " + sample + " " + field); + } catch (DateTimeException ex) { + // expected + } + } + } + } + } + + @Test(groups = "tck") + public void basicTest_get_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + try { + sample.get(field); + fail("Failed on " + sample + " " + field); + } catch (DateTimeException ex) { + // expected + } + } + } + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_get_TemporalField_invalidField() { + for (TemporalAccessor sample : samples()) { + sample.get(MockFieldNoValue.INSTANCE); + } + } + + @Test(groups = "tck") + public void basicTest_get_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + try { + sample.get(null); + fail("Failed on " + sample); + } catch (NullPointerException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + // getLong(TemporalField) + //----------------------------------------------------------------------- + @Test(groups = "tck") + public void basicTest_getLong_TemporalField_supported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : validFields()) { + sample.getLong(field); // no exception + } + } + } + + @Test(groups = "tck") + public void basicTest_getLong_TemporalField_unsupported() { + for (TemporalAccessor sample : samples()) { + for (TemporalField field : invalidFields()) { + try { + sample.getLong(field); + fail("Failed on " + sample + " " + field); + } catch (DateTimeException ex) { + // expected + } + } + } + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_getLong_TemporalField_invalidField() { + for (TemporalAccessor sample : samples()) { + sample.getLong(MockFieldNoValue.INSTANCE); + } + } + + @Test(groups = "tck") + public void basicTest_getLong_TemporalField_null() { + for (TemporalAccessor sample : samples()) { + try { + sample.getLong(null); + fail("Failed on " + sample); + } catch (NullPointerException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void basicTest_query() { + for (TemporalAccessor sample : samples()) { + assertEquals(sample.query(new TemporalQuery() { + @Override + public String queryFrom(TemporalAccessor temporal) { + return "foo"; + } + }), "foo"); + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java new file mode 100644 index 00000000000..ce20d6b9386 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java @@ -0,0 +1,158 @@ +/* + * 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) 2011-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.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamConstants; +import java.io.Serializable; +import java.lang.reflect.Field; + +/** + * Base test class. + */ +public abstract class AbstractTCKTest { + + protected static boolean isIsoLeap(long year) { + if (year % 4 != 0) { + return false; + } + if (year % 100 == 0 && year % 400 != 0) { + return false; + } + return true; + } + + protected static void assertSerializable(Object object) throws IOException, ClassNotFoundException { + assertEquals(object instanceof Serializable, true); + Object deserializedObject = writeThenRead(object); + assertEquals(deserializedObject, object); + } + + private static Object writeThenRead(Object object) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { + oos.writeObject(object); + } + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + return ois.readObject(); + } + } + + protected static void assertSerializedBySer(Object object, byte[] expectedBytes, byte[]... matches) throws Exception { + String serClass = object.getClass().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 (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { + oos.writeObject(object); + } + byte[] bytes = baos.toByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + try (DataInputStream dis = new DataInputStream(bais)) { + assertEquals(dis.readShort(), ObjectStreamConstants.STREAM_MAGIC); + assertEquals(dis.readShort(), ObjectStreamConstants.STREAM_VERSION); + assertEquals(dis.readByte(), ObjectStreamConstants.TC_OBJECT); + assertEquals(dis.readByte(), ObjectStreamConstants.TC_CLASSDESC); + assertEquals(dis.readUTF(), serClass); + assertEquals(dis.readLong(), serVer); + assertEquals(dis.readByte(), ObjectStreamConstants.SC_EXTERNALIZABLE | ObjectStreamConstants.SC_BLOCK_DATA); + assertEquals(dis.readShort(), 0); // number of fields + assertEquals(dis.readByte(), ObjectStreamConstants.TC_ENDBLOCKDATA); // end of classdesc + assertEquals(dis.readByte(), ObjectStreamConstants.TC_NULL); // no superclasses + if (expectedBytes.length < 256) { + assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATA); + assertEquals(dis.readUnsignedByte(), expectedBytes.length); + } else { + assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATALONG); + assertEquals(dis.readInt(), expectedBytes.length); + } + byte[] input = new byte[expectedBytes.length]; + dis.readFully(input); + assertEquals(input, expectedBytes); + if (matches.length > 0) { + for (byte[] match : matches) { + boolean matched = false; + while (matched == false) { + try { + dis.mark(1000); + byte[] possible = new byte[match.length]; + dis.readFully(possible); + assertEquals(possible, match); + matched = true; + } catch (AssertionError ex) { + dis.reset(); + dis.readByte(); // ignore + } + } + } + } else { + assertEquals(dis.readByte(), ObjectStreamConstants.TC_ENDBLOCKDATA); // end of blockdata + assertEquals(dis.read(), -1); + } + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKClock.java b/jdk/test/java/time/tck/java/time/TCKClock.java new file mode 100644 index 00000000000..e4a870e3796 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKClock.java @@ -0,0 +1,128 @@ +/* + * 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 java.time.*; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +/** + * Test Clock. + */ +@Test +public class TCKClock { + + static class MockInstantClock extends Clock { + final long millis; + final ZoneId zone; + MockInstantClock(long millis, ZoneId zone) { + this.millis = millis; + this.zone = zone; + } + @Override + public long millis() { + return millis; + } + @Override + public ZoneId getZone() { + return zone; + } + @Override + public Clock withZone(ZoneId timeZone) { + return new MockInstantClock(millis, timeZone); + } + @Override + public boolean equals(Object obj) { + return false; + } + @Override + public int hashCode() { + return 0; + } + @Override + public String toString() { + return "Mock"; + } + } + + private static final Instant INSTANT = Instant.ofEpochSecond(1873687, 357000000); + private static final ZoneId ZONE = ZoneId.of("Europe/Paris"); + private static final Clock MOCK_INSTANT = new MockInstantClock(INSTANT.toEpochMilli(), ZONE); + + //----------------------------------------------------------------------- + @Test + public void test_mockInstantClock_get() { + assertEquals(MOCK_INSTANT.instant(), INSTANT); + assertEquals(MOCK_INSTANT.millis(), INSTANT.toEpochMilli()); + assertEquals(MOCK_INSTANT.getZone(), ZONE); + } + + @Test + public void test_mockInstantClock_withZone() { + ZoneId london = ZoneId.of("Europe/London"); + Clock changed = MOCK_INSTANT.withZone(london); + assertEquals(MOCK_INSTANT.instant(), INSTANT); + assertEquals(MOCK_INSTANT.millis(), INSTANT.toEpochMilli()); + assertEquals(changed.getZone(), london); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java new file mode 100644 index 00000000000..20e66a2ed96 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java @@ -0,0 +1,166 @@ +/* + * 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.io.IOException; +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test fixed clock. + */ +@Test +public class TCKClock_Fixed extends AbstractTCKTest { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant(); + + //----------------------------------------------------------------------- + public void test_isSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.fixed(INSTANT, ZoneOffset.UTC)); + assertSerializable(Clock.fixed(INSTANT, PARIS)); + } + + //------------------------------------------------------------------------- + public void test_fixed_InstantZoneId() { + Clock test = Clock.fixed(INSTANT, PARIS); + assertEquals(test.instant(), INSTANT); + assertEquals(test.getZone(), PARIS); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_fixed_InstantZoneId_nullInstant() { + Clock.fixed(null, PARIS); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_fixed_InstantZoneId_nullZoneId() { + Clock.fixed(INSTANT, null); + } + + //------------------------------------------------------------------------- + public void test_withZone() { + Clock test = Clock.fixed(INSTANT, PARIS); + Clock changed = test.withZone(MOSCOW); + assertEquals(test.getZone(), PARIS); + assertEquals(changed.getZone(), MOSCOW); + } + + public void test_withZone_equal() { + Clock test = Clock.fixed(INSTANT, PARIS); + Clock changed = test.withZone(PARIS); + assertEquals(changed.getZone(), PARIS); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_withZone_null() { + Clock.fixed(INSTANT, PARIS).withZone(null); + } + + //----------------------------------------------------------------------- + public void test_equals() { + Clock a = Clock.fixed(INSTANT, ZoneOffset.UTC); + Clock b = Clock.fixed(INSTANT, ZoneOffset.UTC); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + + Clock c = Clock.fixed(INSTANT, PARIS); + assertEquals(a.equals(c), false); + + Clock d = Clock.fixed(INSTANT.minusNanos(1), ZoneOffset.UTC); + assertEquals(a.equals(d), false); + + assertEquals(a.equals(null), false); + assertEquals(a.equals("other type"), false); + assertEquals(a.equals(Clock.systemUTC()), false); + } + + public void test_hashCode() { + Clock a = Clock.fixed(INSTANT, ZoneOffset.UTC); + Clock b = Clock.fixed(INSTANT, ZoneOffset.UTC); + assertEquals(a.hashCode(), a.hashCode()); + assertEquals(a.hashCode(), b.hashCode()); + + Clock c = Clock.fixed(INSTANT, PARIS); + assertEquals(a.hashCode() == c.hashCode(), false); + + 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 new file mode 100644 index 00000000000..b628c0ce4eb --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKClock_Offset.java @@ -0,0 +1,176 @@ +/* + * 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 static org.testng.Assert.assertSame; + +import java.io.IOException; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test offset clock. + */ +@Test +public class TCKClock_Offset extends AbstractTCKTest { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant(); + private static final Duration OFFSET = Duration.ofSeconds(2); + + //----------------------------------------------------------------------- + public void test_isSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.offset(Clock.system(PARIS), OFFSET)); + } + + //----------------------------------------------------------------------- + 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)); + assertEquals(test.instant(), INSTANT.plus(OFFSET)); + assertEquals(test.getZone(), PARIS); + } + + public void test_offset_ClockDuration_zeroDuration() { + Clock underlying = Clock.system(PARIS); + Clock test = Clock.offset(underlying, Duration.ZERO); + assertSame(test, underlying); // spec says same + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_offset_ClockDuration_nullClock() { + Clock.offset(null, Duration.ZERO); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_offset_ClockDuration_nullDuration() { + Clock.offset(Clock.systemUTC(), null); + } + + //------------------------------------------------------------------------- + public void test_withZone() { + Clock test = Clock.offset(Clock.system(PARIS), OFFSET); + Clock changed = test.withZone(MOSCOW); + assertEquals(test.getZone(), PARIS); + assertEquals(changed.getZone(), MOSCOW); + } + + public void test_withZone_equal() { + Clock test = Clock.offset(Clock.system(PARIS), OFFSET); + Clock changed = test.withZone(PARIS); + assertEquals(test, changed); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_withZone_null() { + Clock.offset(Clock.system(PARIS), OFFSET).withZone(null); + } + + //----------------------------------------------------------------------- + public void test_equals() { + Clock a = Clock.offset(Clock.system(PARIS), OFFSET); + Clock b = Clock.offset(Clock.system(PARIS), OFFSET); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + + Clock c = Clock.offset(Clock.system(MOSCOW), OFFSET); + assertEquals(a.equals(c), false); + + Clock d = Clock.offset(Clock.system(PARIS), OFFSET.minusNanos(1)); + assertEquals(a.equals(d), false); + + assertEquals(a.equals(null), false); + assertEquals(a.equals("other type"), false); + assertEquals(a.equals(Clock.systemUTC()), false); + } + + public void test_hashCode() { + Clock a = Clock.offset(Clock.system(PARIS), OFFSET); + Clock b = Clock.offset(Clock.system(PARIS), OFFSET); + assertEquals(a.hashCode(), a.hashCode()); + assertEquals(a.hashCode(), b.hashCode()); + + Clock c = Clock.offset(Clock.system(MOSCOW), OFFSET); + assertEquals(a.hashCode() == c.hashCode(), false); + + Clock d = Clock.offset(Clock.system(PARIS), OFFSET.minusNanos(1)); + 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 new file mode 100644 index 00000000000..8152a502ffa --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKClock_System.java @@ -0,0 +1,207 @@ +/* + * 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 static org.testng.Assert.fail; + +import java.io.IOException; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test system clock. + */ +@Test +public class TCKClock_System extends AbstractTCKTest { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + + //----------------------------------------------------------------------- + public void test_isSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.systemUTC()); + assertSerializable(Clock.systemDefaultZone()); + assertSerializable(Clock.system(PARIS)); + } + + //----------------------------------------------------------------------- + public void test_instant() { + Clock system = Clock.systemUTC(); + assertEquals(system.getZone(), ZoneOffset.UTC); + for (int i = 0; i < 10000; i++) { + // assume can eventually get these within 10 milliseconds + Instant instant = system.instant(); + long systemMillis = System.currentTimeMillis(); + if (systemMillis - instant.toEpochMilli() < 10) { + return; // success + } + } + fail(); + } + + public void test_millis() { + Clock system = Clock.systemUTC(); + assertEquals(system.getZone(), ZoneOffset.UTC); + for (int i = 0; i < 10000; i++) { + // assume can eventually get these within 10 milliseconds + long instant = system.millis(); + long systemMillis = System.currentTimeMillis(); + if (systemMillis - instant < 10) { + return; // success + } + } + fail(); + } + + //------------------------------------------------------------------------- + public void test_systemUTC() { + Clock test = Clock.systemUTC(); + assertEquals(test.getZone(), ZoneOffset.UTC); + assertEquals(test, Clock.system(ZoneOffset.UTC)); + } + + public void test_systemDefaultZone() { + Clock test = Clock.systemDefaultZone(); + assertEquals(test.getZone(), ZoneId.systemDefault()); + assertEquals(test, Clock.system(ZoneId.systemDefault())); + } + + public void test_system_ZoneId() { + Clock test = Clock.system(PARIS); + assertEquals(test.getZone(), PARIS); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_zoneId_nullZoneId() { + Clock.system(null); + } + + //------------------------------------------------------------------------- + public void test_withZone() { + Clock test = Clock.system(PARIS); + Clock changed = test.withZone(MOSCOW); + assertEquals(test.getZone(), PARIS); + assertEquals(changed.getZone(), MOSCOW); + } + + public void test_withZone_equal() { + Clock test = Clock.system(PARIS); + Clock changed = test.withZone(PARIS); + assertEquals(changed.getZone(), PARIS); + } + + public void test_withZone_fromUTC() { + Clock test = Clock.systemUTC(); + Clock changed = test.withZone(PARIS); + assertEquals(changed.getZone(), PARIS); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_withZone_null() { + Clock.systemUTC().withZone(null); + } + + //----------------------------------------------------------------------- + public void test_equals() { + Clock a = Clock.systemUTC(); + Clock b = Clock.systemUTC(); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + + Clock c = Clock.system(PARIS); + Clock d = Clock.system(PARIS); + assertEquals(c.equals(c), true); + assertEquals(c.equals(d), true); + assertEquals(d.equals(c), true); + assertEquals(d.equals(d), true); + + assertEquals(a.equals(c), false); + assertEquals(c.equals(a), false); + + assertEquals(a.equals(null), false); + assertEquals(a.equals("other type"), false); + assertEquals(a.equals(Clock.fixed(Instant.now(), ZoneOffset.UTC)), false); + } + + public void test_hashCode() { + Clock a = Clock.system(ZoneOffset.UTC); + Clock b = Clock.system(ZoneOffset.UTC); + assertEquals(a.hashCode(), a.hashCode()); + assertEquals(a.hashCode(), b.hashCode()); + + Clock c = Clock.system(PARIS); + 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 new file mode 100644 index 00000000000..3022d77b747 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java @@ -0,0 +1,260 @@ +/* + * 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 static org.testng.Assert.assertSame; + +import java.io.IOException; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.testng.annotations.Test; + +/** + * Test tick clock. + */ +@Test +public class TCKClock_Tick extends AbstractTCKTest { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final Duration AMOUNT = Duration.ofSeconds(2); + private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)); + private static final Instant INSTANT = ZDT.toInstant(); + + //----------------------------------------------------------------------- + public void test_isSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.tickSeconds(PARIS)); + assertSerializable(Clock.tickMinutes(MOSCOW)); + assertSerializable(Clock.tick(Clock.fixed(INSTANT, PARIS), AMOUNT)); + } + + //----------------------------------------------------------------------- + public void test_tick_ClockDuration_250millis() { + for (int i = 0; i < 1000; i++) { + Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i * 1000_000).toInstant(), PARIS), Duration.ofMillis(250)); + assertEquals(test.instant(), ZDT.withNano((i / 250) * 250_000_000).toInstant()); + assertEquals(test.getZone(), PARIS); + } + } + + public void test_tick_ClockDuration_250micros() { + for (int i = 0; i < 1000; i++) { + Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i * 1000).toInstant(), PARIS), Duration.ofNanos(250_000)); + assertEquals(test.instant(), ZDT.withNano((i / 250) * 250_000).toInstant()); + assertEquals(test.getZone(), PARIS); + } + } + + public void test_tick_ClockDuration_20nanos() { + for (int i = 0; i < 1000; i++) { + Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i).toInstant(), PARIS), Duration.ofNanos(20)); + assertEquals(test.instant(), ZDT.withNano((i / 20) * 20).toInstant()); + assertEquals(test.getZone(), PARIS); + } + } + + public void test_tick_ClockDuration_zeroDuration() { + Clock underlying = Clock.system(PARIS); + Clock test = Clock.tick(underlying, Duration.ZERO); + assertSame(test, underlying); // spec says same + } + + public void test_tick_ClockDuration_1nsDuration() { + Clock underlying = Clock.system(PARIS); + Clock test = Clock.tick(underlying, Duration.ofNanos(1)); + assertSame(test, underlying); // spec says same + } + + @Test(expectedExceptions = ArithmeticException.class) + public void test_tick_ClockDuration_maxDuration() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(Long.MAX_VALUE)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_tick_ClockDuration_subMilliNotDivisible_123ns() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 123)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_tick_ClockDuration_subMilliNotDivisible_999ns() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 999)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_tick_ClockDuration_subMilliNotDivisible_999_999_999ns() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 999_999_999)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_tick_ClockDuration_negative1ns() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, -1)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_tick_ClockDuration_negative1s() { + Clock.tick(Clock.systemUTC(), Duration.ofSeconds(-1)); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_tick_ClockDuration_nullClock() { + Clock.tick(null, Duration.ZERO); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_tick_ClockDuration_nullDuration() { + Clock.tick(Clock.systemUTC(), null); + } + + //----------------------------------------------------------------------- + public void test_tickSeconds_ZoneId() throws Exception { + Clock test = Clock.tickSeconds(PARIS); + assertEquals(test.getZone(), PARIS); + assertEquals(test.instant().getNano(), 0); + Thread.sleep(100); + assertEquals(test.instant().getNano(), 0); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_tickSeconds_ZoneId_nullZoneId() { + Clock.tickSeconds(null); + } + + //----------------------------------------------------------------------- + public void test_tickMinutes_ZoneId() { + Clock test = Clock.tickMinutes(PARIS); + assertEquals(test.getZone(), PARIS); + Instant instant = test.instant(); + assertEquals(instant.getEpochSecond() % 60, 0); + assertEquals(instant.getNano(), 0); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_tickMinutes_ZoneId_nullZoneId() { + Clock.tickMinutes(null); + } + + //------------------------------------------------------------------------- + public void test_withZone() { + Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + Clock changed = test.withZone(MOSCOW); + assertEquals(test.getZone(), PARIS); + assertEquals(changed.getZone(), MOSCOW); + } + + public void test_withZone_equal() { + Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + Clock changed = test.withZone(PARIS); + assertEquals(test, changed); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test_withZone_null() { + Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)).withZone(null); + } + + //----------------------------------------------------------------------- + public void test__equals() { + Clock a = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + Clock b = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + + Clock c = Clock.tick(Clock.system(MOSCOW), Duration.ofMillis(500)); + assertEquals(a.equals(c), false); + + Clock d = Clock.tick(Clock.system(PARIS), Duration.ofMillis(499)); + assertEquals(a.equals(d), false); + + assertEquals(a.equals(null), false); + assertEquals(a.equals("other type"), false); + assertEquals(a.equals(Clock.systemUTC()), false); + } + + public void test_hashCode() { + Clock a = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + Clock b = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + assertEquals(a.hashCode(), a.hashCode()); + assertEquals(a.hashCode(), b.hashCode()); + + Clock c = Clock.tick(Clock.system(MOSCOW), Duration.ofMillis(500)); + assertEquals(a.hashCode() == c.hashCode(), false); + + 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 new file mode 100644 index 00000000000..a2460898039 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java @@ -0,0 +1,351 @@ +/* + * 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 java.time.DayOfWeek.MONDAY; +import static java.time.DayOfWeek.SUNDAY; +import static java.time.DayOfWeek.WEDNESDAY; +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.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 org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DayOfWeek. + */ +@Test +public class TCKDayOfWeek extends AbstractDateTimeTest { + + @BeforeMethod + public void setUp() { + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {MONDAY, WEDNESDAY, SUNDAY, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + DAY_OF_WEEK, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_singleton() { + for (int i = 1; i <= 7; i++) { + DayOfWeek test = DayOfWeek.of(i); + assertEquals(test.getValue(), i); + assertSame(DayOfWeek.of(i), test); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_valueTooLow() { + DayOfWeek.of(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_valueTooHigh() { + DayOfWeek.of(8); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(DayOfWeek.from(LocalDate.of(2011, 6, 6)), DayOfWeek.MONDAY); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + DayOfWeek.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + DayOfWeek.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(DayOfWeek.WEDNESDAY.getLong(ChronoField.DAY_OF_WEEK), 3); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(DayOfWeek.WEDNESDAY.getLong(ChronoField.DAY_OF_WEEK), 3); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query_chrono() { + assertEquals(DayOfWeek.FRIDAY.query(Queries.chrono()), null); + assertEquals(Queries.chrono().queryFrom(DayOfWeek.FRIDAY), null); + } + + @Test + public void test_query_zoneId() { + assertEquals(DayOfWeek.FRIDAY.query(Queries.zoneId()), null); + assertEquals(Queries.zoneId().queryFrom(DayOfWeek.FRIDAY), null); + } + + @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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + DayOfWeek.FRIDAY.query(null); + } + + //----------------------------------------------------------------------- + // getText() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getText() { + assertEquals(DayOfWeek.MONDAY.getText(TextStyle.SHORT, Locale.US), "Mon"); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void test_getText_nullStyle() { + DayOfWeek.MONDAY.getText(null, Locale.US); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void test_getText_nullLocale() { + DayOfWeek.MONDAY.getText(TextStyle.FULL, null); + } + + //----------------------------------------------------------------------- + // plus(long), plus(long,unit) + //----------------------------------------------------------------------- + @DataProvider(name="plus") + Object[][] data_plus() { + return new Object[][] { + {1, -8, 7}, + {1, -7, 1}, + {1, -6, 2}, + {1, -5, 3}, + {1, -4, 4}, + {1, -3, 5}, + {1, -2, 6}, + {1, -1, 7}, + {1, 0, 1}, + {1, 1, 2}, + {1, 2, 3}, + {1, 3, 4}, + {1, 4, 5}, + {1, 5, 6}, + {1, 6, 7}, + {1, 7, 1}, + {1, 8, 2}, + + {1, 1, 2}, + {2, 1, 3}, + {3, 1, 4}, + {4, 1, 5}, + {5, 1, 6}, + {6, 1, 7}, + {7, 1, 1}, + + {1, -1, 7}, + {2, -1, 1}, + {3, -1, 2}, + {4, -1, 3}, + {5, -1, 4}, + {6, -1, 5}, + {7, -1, 6}, + }; + } + + @Test(dataProvider="plus", groups={"tck"}) + public void test_plus_long(int base, long amount, int expected) { + assertEquals(DayOfWeek.of(base).plus(amount), DayOfWeek.of(expected)); + } + + //----------------------------------------------------------------------- + // minus(long), minus(long,unit) + //----------------------------------------------------------------------- + @DataProvider(name="minus") + Object[][] data_minus() { + return new Object[][] { + {1, -8, 2}, + {1, -7, 1}, + {1, -6, 7}, + {1, -5, 6}, + {1, -4, 5}, + {1, -3, 4}, + {1, -2, 3}, + {1, -1, 2}, + {1, 0, 1}, + {1, 1, 7}, + {1, 2, 6}, + {1, 3, 5}, + {1, 4, 4}, + {1, 5, 3}, + {1, 6, 2}, + {1, 7, 1}, + {1, 8, 7}, + }; + } + + @Test(dataProvider="minus", groups={"tck"}) + public void test_minus_long(int base, long amount, int expected) { + assertEquals(DayOfWeek.of(base).minus(amount), DayOfWeek.of(expected)); + } + + //----------------------------------------------------------------------- + // adjustInto() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjustInto() { + assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 2)), LocalDate.of(2012, 8, 27)); + assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 3)), LocalDate.of(2012, 9, 3)); + assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 4)), LocalDate.of(2012, 9, 3)); + assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 10)), LocalDate.of(2012, 9, 10)); + assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 11)), LocalDate.of(2012, 9, 10)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_adjustInto_null() { + DayOfWeek.MONDAY.adjustInto((Temporal) null); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString() { + assertEquals(DayOfWeek.MONDAY.toString(), "MONDAY"); + assertEquals(DayOfWeek.TUESDAY.toString(), "TUESDAY"); + assertEquals(DayOfWeek.WEDNESDAY.toString(), "WEDNESDAY"); + assertEquals(DayOfWeek.THURSDAY.toString(), "THURSDAY"); + assertEquals(DayOfWeek.FRIDAY.toString(), "FRIDAY"); + assertEquals(DayOfWeek.SATURDAY.toString(), "SATURDAY"); + assertEquals(DayOfWeek.SUNDAY.toString(), "SUNDAY"); + } + + //----------------------------------------------------------------------- + // generated methods + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_enum() { + assertEquals(DayOfWeek.valueOf("MONDAY"), DayOfWeek.MONDAY); + assertEquals(DayOfWeek.values()[0], DayOfWeek.MONDAY); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKDuration.java b/jdk/test/java/time/tck/java/time/TCKDuration.java new file mode 100644 index 00000000000..aeba804291d --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKDuration.java @@ -0,0 +1,2135 @@ +/* + * 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) 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; + +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.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.fail; + +import java.io.ByteArrayInputStream; +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.format.DateTimeParseException; +import java.time.temporal.TemporalUnit; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Duration. + */ +@Test +public class TCKDuration extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Duration.ofHours(5)); + assertSerializable(Duration.ofHours(0)); + assertSerializable(Duration.ofHours(-5)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(1); + dos.writeLong(654321); + dos.writeInt(123456789); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Duration.ofSeconds(654321, 123456789), bytes); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_zero() { + assertEquals(Duration.ZERO.getSeconds(), 0L); + assertEquals(Duration.ZERO.getNano(), 0); + } + + //----------------------------------------------------------------------- + // ofSeconds(long) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_seconds_long() { + for (long i = -2; i <= 2; i++) { + Duration t = Duration.ofSeconds(i); + assertEquals(t.getSeconds(), i); + assertEquals(t.getNano(), 0); + } + } + + //----------------------------------------------------------------------- + // ofSeconds(long,long) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_seconds_long_long() { + for (long i = -2; i <= 2; i++) { + for (int j = 0; j < 10; j++) { + Duration t = Duration.ofSeconds(i, j); + assertEquals(t.getSeconds(), i); + assertEquals(t.getNano(), j); + } + for (int j = -10; j < 0; j++) { + Duration t = Duration.ofSeconds(i, j); + assertEquals(t.getSeconds(), i - 1); + assertEquals(t.getNano(), j + 1000000000); + } + for (int j = 999999990; j < 1000000000; j++) { + Duration t = Duration.ofSeconds(i, j); + assertEquals(t.getSeconds(), i); + assertEquals(t.getNano(), j); + } + } + } + + @Test(groups={"tck"}) + public void factory_seconds_long_long_nanosNegativeAdjusted() { + Duration test = Duration.ofSeconds(2L, -1); + assertEquals(test.getSeconds(), 1); + assertEquals(test.getNano(), 999999999); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_seconds_long_long_tooBig() { + Duration.ofSeconds(Long.MAX_VALUE, 1000000000); + } + + //----------------------------------------------------------------------- + // ofMillis(long) + //----------------------------------------------------------------------- + @DataProvider(name="MillisDurationNoNanos") + Object[][] provider_factory_millis_long() { + return new Object[][] { + {0, 0, 0}, + {1, 0, 1000000}, + {2, 0, 2000000}, + {999, 0, 999000000}, + {1000, 1, 0}, + {1001, 1, 1000000}, + {-1, -1, 999000000}, + {-2, -1, 998000000}, + {-999, -1, 1000000}, + {-1000, -1, 0}, + {-1001, -2, 999000000}, + }; + } + + @Test(dataProvider="MillisDurationNoNanos", groups={"tck"}) + public void factory_millis_long(long millis, long expectedSeconds, int expectedNanoOfSecond) { + Duration test = Duration.ofMillis(millis); + assertEquals(test.getSeconds(), expectedSeconds); + assertEquals(test.getNano(), expectedNanoOfSecond); + } + + //----------------------------------------------------------------------- + // ofNanos(long) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_nanos_nanos() { + Duration test = Duration.ofNanos(1); + assertEquals(test.getSeconds(), 0); + assertEquals(test.getNano(), 1); + } + + @Test(groups={"tck"}) + public void factory_nanos_nanosSecs() { + Duration test = Duration.ofNanos(1000000002); + assertEquals(test.getSeconds(), 1); + assertEquals(test.getNano(), 2); + } + + @Test(groups={"tck"}) + public void factory_nanos_negative() { + Duration test = Duration.ofNanos(-2000000001); + assertEquals(test.getSeconds(), -3); + assertEquals(test.getNano(), 999999999); + } + + @Test(groups={"tck"}) + public void factory_nanos_max() { + Duration test = Duration.ofNanos(Long.MAX_VALUE); + assertEquals(test.getSeconds(), Long.MAX_VALUE / 1000000000); + assertEquals(test.getNano(), Long.MAX_VALUE % 1000000000); + } + + @Test(groups={"tck"}) + public void factory_nanos_min() { + Duration test = Duration.ofNanos(Long.MIN_VALUE); + assertEquals(test.getSeconds(), Long.MIN_VALUE / 1000000000 - 1); + assertEquals(test.getNano(), Long.MIN_VALUE % 1000000000 + 1000000000); + } + + //----------------------------------------------------------------------- + // ofMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_minutes() { + Duration test = Duration.ofMinutes(2); + assertEquals(test.getSeconds(), 120); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_minutes_max() { + Duration test = Duration.ofMinutes(Long.MAX_VALUE / 60); + assertEquals(test.getSeconds(), (Long.MAX_VALUE / 60) * 60); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_minutes_min() { + Duration test = Duration.ofMinutes(Long.MIN_VALUE / 60); + assertEquals(test.getSeconds(), (Long.MIN_VALUE / 60) * 60); + assertEquals(test.getNano(), 0); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_minutes_tooBig() { + Duration.ofMinutes(Long.MAX_VALUE / 60 + 1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_minutes_tooSmall() { + Duration.ofMinutes(Long.MIN_VALUE / 60 - 1); + } + + //----------------------------------------------------------------------- + // ofHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_hours() { + Duration test = Duration.ofHours(2); + assertEquals(test.getSeconds(), 2 * 3600); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_hours_max() { + Duration test = Duration.ofHours(Long.MAX_VALUE / 3600); + assertEquals(test.getSeconds(), (Long.MAX_VALUE / 3600) * 3600); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_hours_min() { + Duration test = Duration.ofHours(Long.MIN_VALUE / 3600); + assertEquals(test.getSeconds(), (Long.MIN_VALUE / 3600) * 3600); + assertEquals(test.getNano(), 0); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_hours_tooBig() { + Duration.ofHours(Long.MAX_VALUE / 3600 + 1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_hours_tooSmall() { + Duration.ofHours(Long.MIN_VALUE / 3600 - 1); + } + + //----------------------------------------------------------------------- + // ofDays() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_days() { + Duration test = Duration.ofDays(2); + assertEquals(test.getSeconds(), 2 * 86400); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_days_max() { + Duration test = Duration.ofDays(Long.MAX_VALUE / 86400); + assertEquals(test.getSeconds(), (Long.MAX_VALUE / 86400) * 86400); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_days_min() { + Duration test = Duration.ofDays(Long.MIN_VALUE / 86400); + assertEquals(test.getSeconds(), (Long.MIN_VALUE / 86400) * 86400); + assertEquals(test.getNano(), 0); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_days_tooBig() { + Duration.ofDays(Long.MAX_VALUE / 86400 + 1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_days_tooSmall() { + Duration.ofDays(Long.MIN_VALUE / 86400 - 1); + } + + //----------------------------------------------------------------------- + // of(long,TemporalUnit) + //----------------------------------------------------------------------- + @DataProvider(name="OfTemporalUnit") + Object[][] provider_factory_of_longTemporalUnit() { + return new Object[][] { + {0, NANOS, 0, 0}, + {0, MICROS, 0, 0}, + {0, MILLIS, 0, 0}, + {0, SECONDS, 0, 0}, + {0, MINUTES, 0, 0}, + {0, HOURS, 0, 0}, + {0, HALF_DAYS, 0, 0}, + {0, DAYS, 0, 0}, + {1, NANOS, 0, 1}, + {1, MICROS, 0, 1000}, + {1, MILLIS, 0, 1000000}, + {1, SECONDS, 1, 0}, + {1, MINUTES, 60, 0}, + {1, HOURS, 3600, 0}, + {1, HALF_DAYS, 43200, 0}, + {1, DAYS, 86400, 0}, + {3, NANOS, 0, 3}, + {3, MICROS, 0, 3000}, + {3, MILLIS, 0, 3000000}, + {3, SECONDS, 3, 0}, + {3, MINUTES, 3 * 60, 0}, + {3, HOURS, 3 * 3600, 0}, + {3, HALF_DAYS, 3 * 43200, 0}, + {3, DAYS, 3 * 86400, 0}, + {-1, NANOS, -1, 999999999}, + {-1, MICROS, -1, 999999000}, + {-1, MILLIS, -1, 999000000}, + {-1, SECONDS, -1, 0}, + {-1, MINUTES, -60, 0}, + {-1, HOURS, -3600, 0}, + {-1, HALF_DAYS, -43200, 0}, + {-1, DAYS, -86400, 0}, + {-3, NANOS, -1, 999999997}, + {-3, MICROS, -1, 999997000}, + {-3, MILLIS, -1, 997000000}, + {-3, SECONDS, -3, 0}, + {-3, MINUTES, -3 * 60, 0}, + {-3, HOURS, -3 * 3600, 0}, + {-3, HALF_DAYS, -3 * 43200, 0}, + {-3, DAYS, -3 * 86400, 0}, + {Long.MAX_VALUE, NANOS, Long.MAX_VALUE / 1000000000, (int) (Long.MAX_VALUE % 1000000000)}, + {Long.MIN_VALUE, NANOS, Long.MIN_VALUE / 1000000000 - 1, (int) (Long.MIN_VALUE % 1000000000 + 1000000000)}, + {Long.MAX_VALUE, MICROS, Long.MAX_VALUE / 1000000, (int) ((Long.MAX_VALUE % 1000000) * 1000)}, + {Long.MIN_VALUE, MICROS, Long.MIN_VALUE / 1000000 - 1, (int) ((Long.MIN_VALUE % 1000000 + 1000000) * 1000)}, + {Long.MAX_VALUE, MILLIS, Long.MAX_VALUE / 1000, (int) ((Long.MAX_VALUE % 1000) * 1000000)}, + {Long.MIN_VALUE, MILLIS, Long.MIN_VALUE / 1000 - 1, (int) ((Long.MIN_VALUE % 1000 + 1000) * 1000000)}, + {Long.MAX_VALUE, SECONDS, Long.MAX_VALUE, 0}, + {Long.MIN_VALUE, SECONDS, Long.MIN_VALUE, 0}, + {Long.MAX_VALUE / 60, MINUTES, (Long.MAX_VALUE / 60) * 60, 0}, + {Long.MIN_VALUE / 60, MINUTES, (Long.MIN_VALUE / 60) * 60, 0}, + {Long.MAX_VALUE / 3600, HOURS, (Long.MAX_VALUE / 3600) * 3600, 0}, + {Long.MIN_VALUE / 3600, HOURS, (Long.MIN_VALUE / 3600) * 3600, 0}, + {Long.MAX_VALUE / 43200, HALF_DAYS, (Long.MAX_VALUE / 43200) * 43200, 0}, + {Long.MIN_VALUE / 43200, HALF_DAYS, (Long.MIN_VALUE / 43200) * 43200, 0}, + }; + } + + @Test(dataProvider="OfTemporalUnit", groups={"tck"}) + public void factory_of_longTemporalUnit(long amount, TemporalUnit unit, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.of(amount, unit); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @DataProvider(name="OfTemporalUnitOutOfRange") + Object[][] provider_factory_of_longTemporalUnit_outOfRange() { + return new Object[][] { + {Long.MAX_VALUE / 60 + 1, MINUTES}, + {Long.MIN_VALUE / 60 - 1, MINUTES}, + {Long.MAX_VALUE / 3600 + 1, HOURS}, + {Long.MIN_VALUE / 3600 - 1, HOURS}, + {Long.MAX_VALUE / 43200 + 1, HALF_DAYS}, + {Long.MIN_VALUE / 43200 - 1, HALF_DAYS}, + }; + } + + @Test(dataProvider="OfTemporalUnitOutOfRange", expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void factory_of_longTemporalUnit_outOfRange(long amount, TemporalUnit unit) { + Duration.of(amount, unit); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_longTemporalUnit_estimatedUnit() { + Duration.of(2, WEEKS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_longTemporalUnit_null() { + Duration.of(1, (TemporalUnit) null); + } + + //----------------------------------------------------------------------- + // between() + //----------------------------------------------------------------------- + @DataProvider(name="DurationBetween") + Object[][] provider_factory_between_Instant_Instant() { + return new Object[][] { + {0, 0, 0, 0, 0, 0}, + {3, 0, 7, 0, 4, 0}, + {3, 20, 7, 50, 4, 30}, + {3, 80, 7, 50, 3, 999999970}, + {7, 0, 3, 0, -4, 0}, + }; + } + + @Test(dataProvider="DurationBetween", groups={"tck"}) + public void factory_between_Instant_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); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_between_Instant_Instant_startNull() { + Instant end = Instant.ofEpochSecond(1); + Duration.between(null, end); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_between_Instant_Instant_endNull() { + Instant start = Instant.ofEpochSecond(1); + Duration.between(start, null); + } + + //----------------------------------------------------------------------- + // parse(String) + //----------------------------------------------------------------------- + @DataProvider(name="Parse") + Object[][] provider_factory_parse() { + return new Object[][] { + {"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}, + + {"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}, + + {"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}, + }; + } + + @Test(dataProvider="Parse", groups={"tck"}) + public void factory_parse(String text, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.parse(text); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(dataProvider="Parse", groups={"tck"}) + 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); + } + + @DataProvider(name="ParseFailures") + Object[][] provider_factory_parseFailures() { + return new Object[][] { + {""}, + {"PTS"}, + {"AT0S"}, + {"PA0S"}, + {"PT0A"}, + + {"PT+S"}, + {"PT-S"}, + {"PT.S"}, + {"PTAS"}, + + {"PT+0S"}, + {"PT+00S"}, + {"PT+000S"}, + {"PT-0S"}, + {"PT-00S"}, + {"PT-000S"}, + {"PT+1S"}, + {"PT-.S"}, + {"PT+.S"}, + + {"PT1ABC2S"}, + {"PT1.1ABC2S"}, + + {"PT123456789123456789123456789S"}, + {"PT0.1234567891S"}, + {"PT1.S"}, + {"PT.1S"}, + + {"PT2.-3"}, + {"PT-2.-3"}, + {"PT2.+3"}, + {"PT-2.+3"}, + }; + } + + @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parseFailures(String text) { + Duration.parse(text); + } + + @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parseFailures_comma(String text) { + text = text.replace('.', ','); + Duration.parse(text); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_tooBig() { + Duration.parse("PT" + Long.MAX_VALUE + "1S"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_tooBig_decimal() { + Duration.parse("PT" + Long.MAX_VALUE + "1.1S"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_tooSmall() { + Duration.parse("PT" + Long.MIN_VALUE + "1S"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_tooSmall_decimal() { + Duration.parse("PT" + Long.MIN_VALUE + ".1S"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + Duration.parse((String) null); + } + + @Test(groups={"tck"}) + public void test_deserialization() throws Exception { + Duration orginal = Duration.ofSeconds(2); + 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); + Duration ser = (Duration) in.readObject(); + assertEquals(Duration.ofSeconds(2), ser); + } + + //----------------------------------------------------------------------- + // isZero(), isPositive(), isPositiveOrZero(), isNegative(), isNegativeOrZero() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isZero() { + assertEquals(Duration.ofNanos(0).isZero(), true); + assertEquals(Duration.ofSeconds(0).isZero(), true); + assertEquals(Duration.ofNanos(1).isZero(), false); + assertEquals(Duration.ofSeconds(1).isZero(), false); + assertEquals(Duration.ofSeconds(1, 1).isZero(), false); + assertEquals(Duration.ofNanos(-1).isZero(), false); + assertEquals(Duration.ofSeconds(-1).isZero(), false); + 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"}) + public void test_isNegative() { + assertEquals(Duration.ofNanos(0).isNegative(), false); + assertEquals(Duration.ofSeconds(0).isNegative(), false); + assertEquals(Duration.ofNanos(1).isNegative(), false); + assertEquals(Duration.ofSeconds(1).isNegative(), false); + assertEquals(Duration.ofSeconds(1, 1).isNegative(), false); + assertEquals(Duration.ofNanos(-1).isNegative(), true); + assertEquals(Duration.ofSeconds(-1).isNegative(), true); + assertEquals(Duration.ofSeconds(-1, -1).isNegative(), true); + } + + //----------------------------------------------------------------------- + // plus() + //----------------------------------------------------------------------- + @DataProvider(name="Plus") + Object[][] provider_plus() { + return new Object[][] { + {Long.MIN_VALUE, 0, Long.MAX_VALUE, 0, -1, 0}, + + {-4, 666666667, -4, 666666667, -7, 333333334}, + {-4, 666666667, -3, 0, -7, 666666667}, + {-4, 666666667, -2, 0, -6, 666666667}, + {-4, 666666667, -1, 0, -5, 666666667}, + {-4, 666666667, -1, 333333334, -4, 1}, + {-4, 666666667, -1, 666666667, -4, 333333334}, + {-4, 666666667, -1, 999999999, -4, 666666666}, + {-4, 666666667, 0, 0, -4, 666666667}, + {-4, 666666667, 0, 1, -4, 666666668}, + {-4, 666666667, 0, 333333333, -3, 0}, + {-4, 666666667, 0, 666666666, -3, 333333333}, + {-4, 666666667, 1, 0, -3, 666666667}, + {-4, 666666667, 2, 0, -2, 666666667}, + {-4, 666666667, 3, 0, -1, 666666667}, + {-4, 666666667, 3, 333333333, 0, 0}, + + {-3, 0, -4, 666666667, -7, 666666667}, + {-3, 0, -3, 0, -6, 0}, + {-3, 0, -2, 0, -5, 0}, + {-3, 0, -1, 0, -4, 0}, + {-3, 0, -1, 333333334, -4, 333333334}, + {-3, 0, -1, 666666667, -4, 666666667}, + {-3, 0, -1, 999999999, -4, 999999999}, + {-3, 0, 0, 0, -3, 0}, + {-3, 0, 0, 1, -3, 1}, + {-3, 0, 0, 333333333, -3, 333333333}, + {-3, 0, 0, 666666666, -3, 666666666}, + {-3, 0, 1, 0, -2, 0}, + {-3, 0, 2, 0, -1, 0}, + {-3, 0, 3, 0, 0, 0}, + {-3, 0, 3, 333333333, 0, 333333333}, + + {-2, 0, -4, 666666667, -6, 666666667}, + {-2, 0, -3, 0, -5, 0}, + {-2, 0, -2, 0, -4, 0}, + {-2, 0, -1, 0, -3, 0}, + {-2, 0, -1, 333333334, -3, 333333334}, + {-2, 0, -1, 666666667, -3, 666666667}, + {-2, 0, -1, 999999999, -3, 999999999}, + {-2, 0, 0, 0, -2, 0}, + {-2, 0, 0, 1, -2, 1}, + {-2, 0, 0, 333333333, -2, 333333333}, + {-2, 0, 0, 666666666, -2, 666666666}, + {-2, 0, 1, 0, -1, 0}, + {-2, 0, 2, 0, 0, 0}, + {-2, 0, 3, 0, 1, 0}, + {-2, 0, 3, 333333333, 1, 333333333}, + + {-1, 0, -4, 666666667, -5, 666666667}, + {-1, 0, -3, 0, -4, 0}, + {-1, 0, -2, 0, -3, 0}, + {-1, 0, -1, 0, -2, 0}, + {-1, 0, -1, 333333334, -2, 333333334}, + {-1, 0, -1, 666666667, -2, 666666667}, + {-1, 0, -1, 999999999, -2, 999999999}, + {-1, 0, 0, 0, -1, 0}, + {-1, 0, 0, 1, -1, 1}, + {-1, 0, 0, 333333333, -1, 333333333}, + {-1, 0, 0, 666666666, -1, 666666666}, + {-1, 0, 1, 0, 0, 0}, + {-1, 0, 2, 0, 1, 0}, + {-1, 0, 3, 0, 2, 0}, + {-1, 0, 3, 333333333, 2, 333333333}, + + {-1, 666666667, -4, 666666667, -4, 333333334}, + {-1, 666666667, -3, 0, -4, 666666667}, + {-1, 666666667, -2, 0, -3, 666666667}, + {-1, 666666667, -1, 0, -2, 666666667}, + {-1, 666666667, -1, 333333334, -1, 1}, + {-1, 666666667, -1, 666666667, -1, 333333334}, + {-1, 666666667, -1, 999999999, -1, 666666666}, + {-1, 666666667, 0, 0, -1, 666666667}, + {-1, 666666667, 0, 1, -1, 666666668}, + {-1, 666666667, 0, 333333333, 0, 0}, + {-1, 666666667, 0, 666666666, 0, 333333333}, + {-1, 666666667, 1, 0, 0, 666666667}, + {-1, 666666667, 2, 0, 1, 666666667}, + {-1, 666666667, 3, 0, 2, 666666667}, + {-1, 666666667, 3, 333333333, 3, 0}, + + {0, 0, -4, 666666667, -4, 666666667}, + {0, 0, -3, 0, -3, 0}, + {0, 0, -2, 0, -2, 0}, + {0, 0, -1, 0, -1, 0}, + {0, 0, -1, 333333334, -1, 333333334}, + {0, 0, -1, 666666667, -1, 666666667}, + {0, 0, -1, 999999999, -1, 999999999}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 1}, + {0, 0, 0, 333333333, 0, 333333333}, + {0, 0, 0, 666666666, 0, 666666666}, + {0, 0, 1, 0, 1, 0}, + {0, 0, 2, 0, 2, 0}, + {0, 0, 3, 0, 3, 0}, + {0, 0, 3, 333333333, 3, 333333333}, + + {0, 333333333, -4, 666666667, -3, 0}, + {0, 333333333, -3, 0, -3, 333333333}, + {0, 333333333, -2, 0, -2, 333333333}, + {0, 333333333, -1, 0, -1, 333333333}, + {0, 333333333, -1, 333333334, -1, 666666667}, + {0, 333333333, -1, 666666667, 0, 0}, + {0, 333333333, -1, 999999999, 0, 333333332}, + {0, 333333333, 0, 0, 0, 333333333}, + {0, 333333333, 0, 1, 0, 333333334}, + {0, 333333333, 0, 333333333, 0, 666666666}, + {0, 333333333, 0, 666666666, 0, 999999999}, + {0, 333333333, 1, 0, 1, 333333333}, + {0, 333333333, 2, 0, 2, 333333333}, + {0, 333333333, 3, 0, 3, 333333333}, + {0, 333333333, 3, 333333333, 3, 666666666}, + + {1, 0, -4, 666666667, -3, 666666667}, + {1, 0, -3, 0, -2, 0}, + {1, 0, -2, 0, -1, 0}, + {1, 0, -1, 0, 0, 0}, + {1, 0, -1, 333333334, 0, 333333334}, + {1, 0, -1, 666666667, 0, 666666667}, + {1, 0, -1, 999999999, 0, 999999999}, + {1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 1, 1}, + {1, 0, 0, 333333333, 1, 333333333}, + {1, 0, 0, 666666666, 1, 666666666}, + {1, 0, 1, 0, 2, 0}, + {1, 0, 2, 0, 3, 0}, + {1, 0, 3, 0, 4, 0}, + {1, 0, 3, 333333333, 4, 333333333}, + + {2, 0, -4, 666666667, -2, 666666667}, + {2, 0, -3, 0, -1, 0}, + {2, 0, -2, 0, 0, 0}, + {2, 0, -1, 0, 1, 0}, + {2, 0, -1, 333333334, 1, 333333334}, + {2, 0, -1, 666666667, 1, 666666667}, + {2, 0, -1, 999999999, 1, 999999999}, + {2, 0, 0, 0, 2, 0}, + {2, 0, 0, 1, 2, 1}, + {2, 0, 0, 333333333, 2, 333333333}, + {2, 0, 0, 666666666, 2, 666666666}, + {2, 0, 1, 0, 3, 0}, + {2, 0, 2, 0, 4, 0}, + {2, 0, 3, 0, 5, 0}, + {2, 0, 3, 333333333, 5, 333333333}, + + {3, 0, -4, 666666667, -1, 666666667}, + {3, 0, -3, 0, 0, 0}, + {3, 0, -2, 0, 1, 0}, + {3, 0, -1, 0, 2, 0}, + {3, 0, -1, 333333334, 2, 333333334}, + {3, 0, -1, 666666667, 2, 666666667}, + {3, 0, -1, 999999999, 2, 999999999}, + {3, 0, 0, 0, 3, 0}, + {3, 0, 0, 1, 3, 1}, + {3, 0, 0, 333333333, 3, 333333333}, + {3, 0, 0, 666666666, 3, 666666666}, + {3, 0, 1, 0, 4, 0}, + {3, 0, 2, 0, 5, 0}, + {3, 0, 3, 0, 6, 0}, + {3, 0, 3, 333333333, 6, 333333333}, + + {3, 333333333, -4, 666666667, 0, 0}, + {3, 333333333, -3, 0, 0, 333333333}, + {3, 333333333, -2, 0, 1, 333333333}, + {3, 333333333, -1, 0, 2, 333333333}, + {3, 333333333, -1, 333333334, 2, 666666667}, + {3, 333333333, -1, 666666667, 3, 0}, + {3, 333333333, -1, 999999999, 3, 333333332}, + {3, 333333333, 0, 0, 3, 333333333}, + {3, 333333333, 0, 1, 3, 333333334}, + {3, 333333333, 0, 333333333, 3, 666666666}, + {3, 333333333, 0, 666666666, 3, 999999999}, + {3, 333333333, 1, 0, 4, 333333333}, + {3, 333333333, 2, 0, 5, 333333333}, + {3, 333333333, 3, 0, 6, 333333333}, + {3, 333333333, 3, 333333333, 6, 666666666}, + + {Long.MAX_VALUE, 0, Long.MIN_VALUE, 0, -1, 0}, + }; + } + + @Test(dataProvider="Plus", groups={"tck"}) + public void plus(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos).plus(Duration.ofSeconds(otherSeconds, otherNanos)); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void plusOverflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999); + t.plus(Duration.ofSeconds(0, 1)); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void plusOverflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE); + t.plus(Duration.ofSeconds(-1, 999999999)); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void plus_longTemporalUnit_seconds() { + Duration t = Duration.ofSeconds(1); + t = t.plus(1, SECONDS); + assertEquals(2, t.getSeconds()); + assertEquals(0, t.getNano()); + } + + @Test(groups={"tck"}) + public void plus_longTemporalUnit_millis() { + Duration t = Duration.ofSeconds(1); + t = t.plus(1, MILLIS); + assertEquals(1, t.getSeconds()); + assertEquals(1000000, t.getNano()); + } + + @Test(groups={"tck"}) + public void plus_longTemporalUnit_micros() { + Duration t = Duration.ofSeconds(1); + t = t.plus(1, MICROS); + assertEquals(1, t.getSeconds()); + assertEquals(1000, t.getNano()); + } + + @Test(groups={"tck"}) + public void plus_longTemporalUnit_nanos() { + Duration t = Duration.ofSeconds(1); + t = t.plus(1, NANOS); + assertEquals(1, t.getSeconds()); + assertEquals(1, t.getNano()); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void plus_longTemporalUnit_null() { + Duration t = Duration.ofSeconds(1); + t.plus(1, (TemporalUnit) null); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusSeconds") + Object[][] provider_plusSeconds_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {0, 0, -1, -1, 0}, + {0, 0, Long.MAX_VALUE, Long.MAX_VALUE, 0}, + {0, 0, Long.MIN_VALUE, Long.MIN_VALUE, 0}, + {1, 0, 0, 1, 0}, + {1, 0, 1, 2, 0}, + {1, 0, -1, 0, 0}, + {1, 0, Long.MAX_VALUE - 1, Long.MAX_VALUE, 0}, + {1, 0, Long.MIN_VALUE, Long.MIN_VALUE + 1, 0}, + {1, 1, 0, 1, 1}, + {1, 1, 1, 2, 1}, + {1, 1, -1, 0, 1}, + {1, 1, Long.MAX_VALUE - 1, Long.MAX_VALUE, 1}, + {1, 1, Long.MIN_VALUE, Long.MIN_VALUE + 1, 1}, + {-1, 1, 0, -1, 1}, + {-1, 1, 1, 0, 1}, + {-1, 1, -1, -2, 1}, + {-1, 1, Long.MAX_VALUE, Long.MAX_VALUE - 1, 1}, + {-1, 1, Long.MIN_VALUE + 1, Long.MIN_VALUE, 1}, + }; + } + + @Test(dataProvider="PlusSeconds", groups={"tck"}) + public void plusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.plusSeconds(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusSeconds_long_overflowTooBig() { + Duration t = Duration.ofSeconds(1, 0); + t.plusSeconds(Long.MAX_VALUE); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusSeconds_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(-1, 0); + t.plusSeconds(Long.MIN_VALUE); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusMillis") + Object[][] provider_plusMillis_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1000000}, + {0, 0, 999, 0, 999000000}, + {0, 0, 1000, 1, 0}, + {0, 0, 1001, 1, 1000000}, + {0, 0, 1999, 1, 999000000}, + {0, 0, 2000, 2, 0}, + {0, 0, -1, -1, 999000000}, + {0, 0, -999, -1, 1000000}, + {0, 0, -1000, -1, 0}, + {0, 0, -1001, -2, 999000000}, + {0, 0, -1999, -2, 1000000}, + + {0, 1, 0, 0, 1}, + {0, 1, 1, 0, 1000001}, + {0, 1, 998, 0, 998000001}, + {0, 1, 999, 0, 999000001}, + {0, 1, 1000, 1, 1}, + {0, 1, 1998, 1, 998000001}, + {0, 1, 1999, 1, 999000001}, + {0, 1, 2000, 2, 1}, + {0, 1, -1, -1, 999000001}, + {0, 1, -2, -1, 998000001}, + {0, 1, -1000, -1, 1}, + {0, 1, -1001, -2, 999000001}, + + {0, 1000000, 0, 0, 1000000}, + {0, 1000000, 1, 0, 2000000}, + {0, 1000000, 998, 0, 999000000}, + {0, 1000000, 999, 1, 0}, + {0, 1000000, 1000, 1, 1000000}, + {0, 1000000, 1998, 1, 999000000}, + {0, 1000000, 1999, 2, 0}, + {0, 1000000, 2000, 2, 1000000}, + {0, 1000000, -1, 0, 0}, + {0, 1000000, -2, -1, 999000000}, + {0, 1000000, -999, -1, 2000000}, + {0, 1000000, -1000, -1, 1000000}, + {0, 1000000, -1001, -1, 0}, + {0, 1000000, -1002, -2, 999000000}, + + {0, 999999999, 0, 0, 999999999}, + {0, 999999999, 1, 1, 999999}, + {0, 999999999, 999, 1, 998999999}, + {0, 999999999, 1000, 1, 999999999}, + {0, 999999999, 1001, 2, 999999}, + {0, 999999999, -1, 0, 998999999}, + {0, 999999999, -1000, -1, 999999999}, + {0, 999999999, -1001, -1, 998999999}, + }; + } + + @Test(dataProvider="PlusMillis", groups={"tck"}) + public void plusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.plusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="PlusMillis", groups={"tck"}) + public void plusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds + 1, nanos); + t = t.plusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds + 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="PlusMillis", groups={"tck"}) + public void plusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds - 1, nanos); + t = t.plusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds - 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(groups={"tck"}) + public void plusMillis_long_max() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 998999999); + t = t.plusMillis(1); + assertEquals(t.getSeconds(), Long.MAX_VALUE); + assertEquals(t.getNano(), 999999999); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusMillis_long_overflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999000000); + t.plusMillis(1); + } + + @Test(groups={"tck"}) + public void plusMillis_long_min() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 1000000); + t = t.plusMillis(-1); + assertEquals(t.getSeconds(), Long.MIN_VALUE); + assertEquals(t.getNano(), 0); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusMillis_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0); + t.plusMillis(-1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusNanos") + Object[][] provider_plusNanos_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1}, + {0, 0, 999999999, 0, 999999999}, + {0, 0, 1000000000, 1, 0}, + {0, 0, 1000000001, 1, 1}, + {0, 0, 1999999999, 1, 999999999}, + {0, 0, 2000000000, 2, 0}, + {0, 0, -1, -1, 999999999}, + {0, 0, -999999999, -1, 1}, + {0, 0, -1000000000, -1, 0}, + {0, 0, -1000000001, -2, 999999999}, + {0, 0, -1999999999, -2, 1}, + + {1, 0, 0, 1, 0}, + {1, 0, 1, 1, 1}, + {1, 0, 999999999, 1, 999999999}, + {1, 0, 1000000000, 2, 0}, + {1, 0, 1000000001, 2, 1}, + {1, 0, 1999999999, 2, 999999999}, + {1, 0, 2000000000, 3, 0}, + {1, 0, -1, 0, 999999999}, + {1, 0, -999999999, 0, 1}, + {1, 0, -1000000000, 0, 0}, + {1, 0, -1000000001, -1, 999999999}, + {1, 0, -1999999999, -1, 1}, + + {-1, 0, 0, -1, 0}, + {-1, 0, 1, -1, 1}, + {-1, 0, 999999999, -1, 999999999}, + {-1, 0, 1000000000, 0, 0}, + {-1, 0, 1000000001, 0, 1}, + {-1, 0, 1999999999, 0, 999999999}, + {-1, 0, 2000000000, 1, 0}, + {-1, 0, -1, -2, 999999999}, + {-1, 0, -999999999, -2, 1}, + {-1, 0, -1000000000, -2, 0}, + {-1, 0, -1000000001, -3, 999999999}, + {-1, 0, -1999999999, -3, 1}, + + {1, 1, 0, 1, 1}, + {1, 1, 1, 1, 2}, + {1, 1, 999999998, 1, 999999999}, + {1, 1, 999999999, 2, 0}, + {1, 1, 1000000000, 2, 1}, + {1, 1, 1999999998, 2, 999999999}, + {1, 1, 1999999999, 3, 0}, + {1, 1, 2000000000, 3, 1}, + {1, 1, -1, 1, 0}, + {1, 1, -2, 0, 999999999}, + {1, 1, -1000000000, 0, 1}, + {1, 1, -1000000001, 0, 0}, + {1, 1, -1000000002, -1, 999999999}, + {1, 1, -2000000000, -1, 1}, + + {1, 999999999, 0, 1, 999999999}, + {1, 999999999, 1, 2, 0}, + {1, 999999999, 999999999, 2, 999999998}, + {1, 999999999, 1000000000, 2, 999999999}, + {1, 999999999, 1000000001, 3, 0}, + {1, 999999999, -1, 1, 999999998}, + {1, 999999999, -1000000000, 0, 999999999}, + {1, 999999999, -1000000001, 0, 999999998}, + {1, 999999999, -1999999999, 0, 0}, + {1, 999999999, -2000000000, -1, 999999999}, + + {Long.MAX_VALUE, 0, 999999999, Long.MAX_VALUE, 999999999}, + {Long.MAX_VALUE - 1, 0, 1999999999, Long.MAX_VALUE, 999999999}, + {Long.MIN_VALUE, 1, -1, Long.MIN_VALUE, 0}, + {Long.MIN_VALUE + 1, 1, -1000000001, Long.MIN_VALUE, 0}, + }; + } + + @Test(dataProvider="PlusNanos", groups={"tck"}) + public void plusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.plusNanos(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusNanos_long_overflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999); + t.plusNanos(1); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void plusNanos_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0); + t.plusNanos(-1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Minus") + Object[][] provider_minus() { + return new Object[][] { + {Long.MIN_VALUE, 0, Long.MIN_VALUE + 1, 0, -1, 0}, + + {-4, 666666667, -4, 666666667, 0, 0}, + {-4, 666666667, -3, 0, -1, 666666667}, + {-4, 666666667, -2, 0, -2, 666666667}, + {-4, 666666667, -1, 0, -3, 666666667}, + {-4, 666666667, -1, 333333334, -3, 333333333}, + {-4, 666666667, -1, 666666667, -3, 0}, + {-4, 666666667, -1, 999999999, -4, 666666668}, + {-4, 666666667, 0, 0, -4, 666666667}, + {-4, 666666667, 0, 1, -4, 666666666}, + {-4, 666666667, 0, 333333333, -4, 333333334}, + {-4, 666666667, 0, 666666666, -4, 1}, + {-4, 666666667, 1, 0, -5, 666666667}, + {-4, 666666667, 2, 0, -6, 666666667}, + {-4, 666666667, 3, 0, -7, 666666667}, + {-4, 666666667, 3, 333333333, -7, 333333334}, + + {-3, 0, -4, 666666667, 0, 333333333}, + {-3, 0, -3, 0, 0, 0}, + {-3, 0, -2, 0, -1, 0}, + {-3, 0, -1, 0, -2, 0}, + {-3, 0, -1, 333333334, -3, 666666666}, + {-3, 0, -1, 666666667, -3, 333333333}, + {-3, 0, -1, 999999999, -3, 1}, + {-3, 0, 0, 0, -3, 0}, + {-3, 0, 0, 1, -4, 999999999}, + {-3, 0, 0, 333333333, -4, 666666667}, + {-3, 0, 0, 666666666, -4, 333333334}, + {-3, 0, 1, 0, -4, 0}, + {-3, 0, 2, 0, -5, 0}, + {-3, 0, 3, 0, -6, 0}, + {-3, 0, 3, 333333333, -7, 666666667}, + + {-2, 0, -4, 666666667, 1, 333333333}, + {-2, 0, -3, 0, 1, 0}, + {-2, 0, -2, 0, 0, 0}, + {-2, 0, -1, 0, -1, 0}, + {-2, 0, -1, 333333334, -2, 666666666}, + {-2, 0, -1, 666666667, -2, 333333333}, + {-2, 0, -1, 999999999, -2, 1}, + {-2, 0, 0, 0, -2, 0}, + {-2, 0, 0, 1, -3, 999999999}, + {-2, 0, 0, 333333333, -3, 666666667}, + {-2, 0, 0, 666666666, -3, 333333334}, + {-2, 0, 1, 0, -3, 0}, + {-2, 0, 2, 0, -4, 0}, + {-2, 0, 3, 0, -5, 0}, + {-2, 0, 3, 333333333, -6, 666666667}, + + {-1, 0, -4, 666666667, 2, 333333333}, + {-1, 0, -3, 0, 2, 0}, + {-1, 0, -2, 0, 1, 0}, + {-1, 0, -1, 0, 0, 0}, + {-1, 0, -1, 333333334, -1, 666666666}, + {-1, 0, -1, 666666667, -1, 333333333}, + {-1, 0, -1, 999999999, -1, 1}, + {-1, 0, 0, 0, -1, 0}, + {-1, 0, 0, 1, -2, 999999999}, + {-1, 0, 0, 333333333, -2, 666666667}, + {-1, 0, 0, 666666666, -2, 333333334}, + {-1, 0, 1, 0, -2, 0}, + {-1, 0, 2, 0, -3, 0}, + {-1, 0, 3, 0, -4, 0}, + {-1, 0, 3, 333333333, -5, 666666667}, + + {-1, 666666667, -4, 666666667, 3, 0}, + {-1, 666666667, -3, 0, 2, 666666667}, + {-1, 666666667, -2, 0, 1, 666666667}, + {-1, 666666667, -1, 0, 0, 666666667}, + {-1, 666666667, -1, 333333334, 0, 333333333}, + {-1, 666666667, -1, 666666667, 0, 0}, + {-1, 666666667, -1, 999999999, -1, 666666668}, + {-1, 666666667, 0, 0, -1, 666666667}, + {-1, 666666667, 0, 1, -1, 666666666}, + {-1, 666666667, 0, 333333333, -1, 333333334}, + {-1, 666666667, 0, 666666666, -1, 1}, + {-1, 666666667, 1, 0, -2, 666666667}, + {-1, 666666667, 2, 0, -3, 666666667}, + {-1, 666666667, 3, 0, -4, 666666667}, + {-1, 666666667, 3, 333333333, -4, 333333334}, + + {0, 0, -4, 666666667, 3, 333333333}, + {0, 0, -3, 0, 3, 0}, + {0, 0, -2, 0, 2, 0}, + {0, 0, -1, 0, 1, 0}, + {0, 0, -1, 333333334, 0, 666666666}, + {0, 0, -1, 666666667, 0, 333333333}, + {0, 0, -1, 999999999, 0, 1}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, -1, 999999999}, + {0, 0, 0, 333333333, -1, 666666667}, + {0, 0, 0, 666666666, -1, 333333334}, + {0, 0, 1, 0, -1, 0}, + {0, 0, 2, 0, -2, 0}, + {0, 0, 3, 0, -3, 0}, + {0, 0, 3, 333333333, -4, 666666667}, + + {0, 333333333, -4, 666666667, 3, 666666666}, + {0, 333333333, -3, 0, 3, 333333333}, + {0, 333333333, -2, 0, 2, 333333333}, + {0, 333333333, -1, 0, 1, 333333333}, + {0, 333333333, -1, 333333334, 0, 999999999}, + {0, 333333333, -1, 666666667, 0, 666666666}, + {0, 333333333, -1, 999999999, 0, 333333334}, + {0, 333333333, 0, 0, 0, 333333333}, + {0, 333333333, 0, 1, 0, 333333332}, + {0, 333333333, 0, 333333333, 0, 0}, + {0, 333333333, 0, 666666666, -1, 666666667}, + {0, 333333333, 1, 0, -1, 333333333}, + {0, 333333333, 2, 0, -2, 333333333}, + {0, 333333333, 3, 0, -3, 333333333}, + {0, 333333333, 3, 333333333, -3, 0}, + + {1, 0, -4, 666666667, 4, 333333333}, + {1, 0, -3, 0, 4, 0}, + {1, 0, -2, 0, 3, 0}, + {1, 0, -1, 0, 2, 0}, + {1, 0, -1, 333333334, 1, 666666666}, + {1, 0, -1, 666666667, 1, 333333333}, + {1, 0, -1, 999999999, 1, 1}, + {1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 999999999}, + {1, 0, 0, 333333333, 0, 666666667}, + {1, 0, 0, 666666666, 0, 333333334}, + {1, 0, 1, 0, 0, 0}, + {1, 0, 2, 0, -1, 0}, + {1, 0, 3, 0, -2, 0}, + {1, 0, 3, 333333333, -3, 666666667}, + + {2, 0, -4, 666666667, 5, 333333333}, + {2, 0, -3, 0, 5, 0}, + {2, 0, -2, 0, 4, 0}, + {2, 0, -1, 0, 3, 0}, + {2, 0, -1, 333333334, 2, 666666666}, + {2, 0, -1, 666666667, 2, 333333333}, + {2, 0, -1, 999999999, 2, 1}, + {2, 0, 0, 0, 2, 0}, + {2, 0, 0, 1, 1, 999999999}, + {2, 0, 0, 333333333, 1, 666666667}, + {2, 0, 0, 666666666, 1, 333333334}, + {2, 0, 1, 0, 1, 0}, + {2, 0, 2, 0, 0, 0}, + {2, 0, 3, 0, -1, 0}, + {2, 0, 3, 333333333, -2, 666666667}, + + {3, 0, -4, 666666667, 6, 333333333}, + {3, 0, -3, 0, 6, 0}, + {3, 0, -2, 0, 5, 0}, + {3, 0, -1, 0, 4, 0}, + {3, 0, -1, 333333334, 3, 666666666}, + {3, 0, -1, 666666667, 3, 333333333}, + {3, 0, -1, 999999999, 3, 1}, + {3, 0, 0, 0, 3, 0}, + {3, 0, 0, 1, 2, 999999999}, + {3, 0, 0, 333333333, 2, 666666667}, + {3, 0, 0, 666666666, 2, 333333334}, + {3, 0, 1, 0, 2, 0}, + {3, 0, 2, 0, 1, 0}, + {3, 0, 3, 0, 0, 0}, + {3, 0, 3, 333333333, -1, 666666667}, + + {3, 333333333, -4, 666666667, 6, 666666666}, + {3, 333333333, -3, 0, 6, 333333333}, + {3, 333333333, -2, 0, 5, 333333333}, + {3, 333333333, -1, 0, 4, 333333333}, + {3, 333333333, -1, 333333334, 3, 999999999}, + {3, 333333333, -1, 666666667, 3, 666666666}, + {3, 333333333, -1, 999999999, 3, 333333334}, + {3, 333333333, 0, 0, 3, 333333333}, + {3, 333333333, 0, 1, 3, 333333332}, + {3, 333333333, 0, 333333333, 3, 0}, + {3, 333333333, 0, 666666666, 2, 666666667}, + {3, 333333333, 1, 0, 2, 333333333}, + {3, 333333333, 2, 0, 1, 333333333}, + {3, 333333333, 3, 0, 0, 333333333}, + {3, 333333333, 3, 333333333, 0, 0}, + + {Long.MAX_VALUE, 0, Long.MAX_VALUE, 0, 0, 0}, + }; + } + + @Test(dataProvider="Minus", groups={"tck"}) + public void minus(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos).minus(Duration.ofSeconds(otherSeconds, otherNanos)); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void minusOverflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE); + t.minus(Duration.ofSeconds(0, 1)); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void minusOverflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999); + t.minus(Duration.ofSeconds(-1, 999999999)); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void minus_longTemporalUnit_seconds() { + Duration t = Duration.ofSeconds(1); + t = t.minus(1, SECONDS); + assertEquals(0, t.getSeconds()); + assertEquals(0, t.getNano()); + } + + @Test(groups={"tck"}) + public void minus_longTemporalUnit_millis() { + Duration t = Duration.ofSeconds(1); + t = t.minus(1, MILLIS); + assertEquals(0, t.getSeconds()); + assertEquals(999000000, t.getNano()); + } + + @Test(groups={"tck"}) + public void minus_longTemporalUnit_micros() { + Duration t = Duration.ofSeconds(1); + t = t.minus(1, MICROS); + assertEquals(0, t.getSeconds()); + assertEquals(999999000, t.getNano()); + } + + @Test(groups={"tck"}) + public void minus_longTemporalUnit_nanos() { + Duration t = Duration.ofSeconds(1); + t = t.minus(1, NANOS); + assertEquals(0, t.getSeconds()); + assertEquals(999999999, t.getNano()); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void minus_longTemporalUnit_null() { + Duration t = Duration.ofSeconds(1); + t.minus(1, (TemporalUnit) null); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusSeconds") + Object[][] provider_minusSeconds_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 0}, + {0, 0, -1, 1, 0}, + {0, 0, Long.MAX_VALUE, -Long.MAX_VALUE, 0}, + {0, 0, Long.MIN_VALUE + 1, Long.MAX_VALUE, 0}, + {1, 0, 0, 1, 0}, + {1, 0, 1, 0, 0}, + {1, 0, -1, 2, 0}, + {1, 0, Long.MAX_VALUE - 1, -Long.MAX_VALUE + 2, 0}, + {1, 0, Long.MIN_VALUE + 2, Long.MAX_VALUE, 0}, + {1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1}, + {1, 1, -1, 2, 1}, + {1, 1, Long.MAX_VALUE, -Long.MAX_VALUE + 1, 1}, + {1, 1, Long.MIN_VALUE + 2, Long.MAX_VALUE, 1}, + {-1, 1, 0, -1, 1}, + {-1, 1, 1, -2, 1}, + {-1, 1, -1, 0, 1}, + {-1, 1, Long.MAX_VALUE, Long.MIN_VALUE, 1}, + {-1, 1, Long.MIN_VALUE + 1, Long.MAX_VALUE - 1, 1}, + }; + } + + @Test(dataProvider="MinusSeconds", groups={"tck"}) + public void minusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.minusSeconds(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusSeconds_long_overflowTooBig() { + Duration t = Duration.ofSeconds(1, 0); + t.minusSeconds(Long.MIN_VALUE + 1); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusSeconds_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(-2, 0); + t.minusSeconds(Long.MAX_VALUE); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusMillis") + Object[][] provider_minusMillis_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 999000000}, + {0, 0, 999, -1, 1000000}, + {0, 0, 1000, -1, 0}, + {0, 0, 1001, -2, 999000000}, + {0, 0, 1999, -2, 1000000}, + {0, 0, 2000, -2, 0}, + {0, 0, -1, 0, 1000000}, + {0, 0, -999, 0, 999000000}, + {0, 0, -1000, 1, 0}, + {0, 0, -1001, 1, 1000000}, + {0, 0, -1999, 1, 999000000}, + + {0, 1, 0, 0, 1}, + {0, 1, 1, -1, 999000001}, + {0, 1, 998, -1, 2000001}, + {0, 1, 999, -1, 1000001}, + {0, 1, 1000, -1, 1}, + {0, 1, 1998, -2, 2000001}, + {0, 1, 1999, -2, 1000001}, + {0, 1, 2000, -2, 1}, + {0, 1, -1, 0, 1000001}, + {0, 1, -2, 0, 2000001}, + {0, 1, -1000, 1, 1}, + {0, 1, -1001, 1, 1000001}, + + {0, 1000000, 0, 0, 1000000}, + {0, 1000000, 1, 0, 0}, + {0, 1000000, 998, -1, 3000000}, + {0, 1000000, 999, -1, 2000000}, + {0, 1000000, 1000, -1, 1000000}, + {0, 1000000, 1998, -2, 3000000}, + {0, 1000000, 1999, -2, 2000000}, + {0, 1000000, 2000, -2, 1000000}, + {0, 1000000, -1, 0, 2000000}, + {0, 1000000, -2, 0, 3000000}, + {0, 1000000, -999, 1, 0}, + {0, 1000000, -1000, 1, 1000000}, + {0, 1000000, -1001, 1, 2000000}, + {0, 1000000, -1002, 1, 3000000}, + + {0, 999999999, 0, 0, 999999999}, + {0, 999999999, 1, 0, 998999999}, + {0, 999999999, 999, 0, 999999}, + {0, 999999999, 1000, -1, 999999999}, + {0, 999999999, 1001, -1, 998999999}, + {0, 999999999, -1, 1, 999999}, + {0, 999999999, -1000, 1, 999999999}, + {0, 999999999, -1001, 2, 999999}, + }; + } + + @Test(dataProvider="MinusMillis", groups={"tck"}) + public void minusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.minusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="MinusMillis", groups={"tck"}) + public void minusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds + 1, nanos); + t = t.minusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds + 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="MinusMillis", groups={"tck"}) + public void minusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds - 1, nanos); + t = t.minusMillis(amount); + assertEquals(t.getSeconds(), expectedSeconds - 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(groups={"tck"}) + public void minusMillis_long_max() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 998999999); + t = t.minusMillis(-1); + assertEquals(t.getSeconds(), Long.MAX_VALUE); + assertEquals(t.getNano(), 999999999); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusMillis_long_overflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999000000); + t.minusMillis(-1); + } + + @Test(groups={"tck"}) + public void minusMillis_long_min() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 1000000); + t = t.minusMillis(1); + assertEquals(t.getSeconds(), Long.MIN_VALUE); + assertEquals(t.getNano(), 0); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusMillis_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0); + t.minusMillis(1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusNanos") + Object[][] provider_minusNanos_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 999999999}, + {0, 0, 999999999, -1, 1}, + {0, 0, 1000000000, -1, 0}, + {0, 0, 1000000001, -2, 999999999}, + {0, 0, 1999999999, -2, 1}, + {0, 0, 2000000000, -2, 0}, + {0, 0, -1, 0, 1}, + {0, 0, -999999999, 0, 999999999}, + {0, 0, -1000000000, 1, 0}, + {0, 0, -1000000001, 1, 1}, + {0, 0, -1999999999, 1, 999999999}, + + {1, 0, 0, 1, 0}, + {1, 0, 1, 0, 999999999}, + {1, 0, 999999999, 0, 1}, + {1, 0, 1000000000, 0, 0}, + {1, 0, 1000000001, -1, 999999999}, + {1, 0, 1999999999, -1, 1}, + {1, 0, 2000000000, -1, 0}, + {1, 0, -1, 1, 1}, + {1, 0, -999999999, 1, 999999999}, + {1, 0, -1000000000, 2, 0}, + {1, 0, -1000000001, 2, 1}, + {1, 0, -1999999999, 2, 999999999}, + + {-1, 0, 0, -1, 0}, + {-1, 0, 1, -2, 999999999}, + {-1, 0, 999999999, -2, 1}, + {-1, 0, 1000000000, -2, 0}, + {-1, 0, 1000000001, -3, 999999999}, + {-1, 0, 1999999999, -3, 1}, + {-1, 0, 2000000000, -3, 0}, + {-1, 0, -1, -1, 1}, + {-1, 0, -999999999, -1, 999999999}, + {-1, 0, -1000000000, 0, 0}, + {-1, 0, -1000000001, 0, 1}, + {-1, 0, -1999999999, 0, 999999999}, + + {1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0}, + {1, 1, 999999998, 0, 3}, + {1, 1, 999999999, 0, 2}, + {1, 1, 1000000000, 0, 1}, + {1, 1, 1999999998, -1, 3}, + {1, 1, 1999999999, -1, 2}, + {1, 1, 2000000000, -1, 1}, + {1, 1, -1, 1, 2}, + {1, 1, -2, 1, 3}, + {1, 1, -1000000000, 2, 1}, + {1, 1, -1000000001, 2, 2}, + {1, 1, -1000000002, 2, 3}, + {1, 1, -2000000000, 3, 1}, + + {1, 999999999, 0, 1, 999999999}, + {1, 999999999, 1, 1, 999999998}, + {1, 999999999, 999999999, 1, 0}, + {1, 999999999, 1000000000, 0, 999999999}, + {1, 999999999, 1000000001, 0, 999999998}, + {1, 999999999, -1, 2, 0}, + {1, 999999999, -1000000000, 2, 999999999}, + {1, 999999999, -1000000001, 3, 0}, + {1, 999999999, -1999999999, 3, 999999998}, + {1, 999999999, -2000000000, 3, 999999999}, + + {Long.MAX_VALUE, 0, -999999999, Long.MAX_VALUE, 999999999}, + {Long.MAX_VALUE - 1, 0, -1999999999, Long.MAX_VALUE, 999999999}, + {Long.MIN_VALUE, 1, 1, Long.MIN_VALUE, 0}, + {Long.MIN_VALUE + 1, 1, 1000000001, Long.MIN_VALUE, 0}, + }; + } + + @Test(dataProvider="MinusNanos", groups={"tck"}) + public void minusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.minusNanos(amount); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusNanos_long_overflowTooBig() { + Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999); + t.minusNanos(-1); + } + + @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"}) + public void minusNanos_long_overflowTooSmall() { + Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0); + t.minusNanos(1); + } + + //----------------------------------------------------------------------- + // multipliedBy() + //----------------------------------------------------------------------- + @DataProvider(name="MultipliedBy") + Object[][] provider_multipliedBy() { + return new Object[][] { + {-4, 666666667, -3, 9, 999999999}, + {-4, 666666667, -2, 6, 666666666}, + {-4, 666666667, -1, 3, 333333333}, + {-4, 666666667, 0, 0, 0}, + {-4, 666666667, 1, -4, 666666667}, + {-4, 666666667, 2, -7, 333333334}, + {-4, 666666667, 3, -10, 000000001}, + + {-3, 0, -3, 9, 0}, + {-3, 0, -2, 6, 0}, + {-3, 0, -1, 3, 0}, + {-3, 0, 0, 0, 0}, + {-3, 0, 1, -3, 0}, + {-3, 0, 2, -6, 0}, + {-3, 0, 3, -9, 0}, + + {-2, 0, -3, 6, 0}, + {-2, 0, -2, 4, 0}, + {-2, 0, -1, 2, 0}, + {-2, 0, 0, 0, 0}, + {-2, 0, 1, -2, 0}, + {-2, 0, 2, -4, 0}, + {-2, 0, 3, -6, 0}, + + {-1, 0, -3, 3, 0}, + {-1, 0, -2, 2, 0}, + {-1, 0, -1, 1, 0}, + {-1, 0, 0, 0, 0}, + {-1, 0, 1, -1, 0}, + {-1, 0, 2, -2, 0}, + {-1, 0, 3, -3, 0}, + + {-1, 500000000, -3, 1, 500000000}, + {-1, 500000000, -2, 1, 0}, + {-1, 500000000, -1, 0, 500000000}, + {-1, 500000000, 0, 0, 0}, + {-1, 500000000, 1, -1, 500000000}, + {-1, 500000000, 2, -1, 0}, + {-1, 500000000, 3, -2, 500000000}, + + {0, 0, -3, 0, 0}, + {0, 0, -2, 0, 0}, + {0, 0, -1, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 2, 0, 0}, + {0, 0, 3, 0, 0}, + + {0, 500000000, -3, -2, 500000000}, + {0, 500000000, -2, -1, 0}, + {0, 500000000, -1, -1, 500000000}, + {0, 500000000, 0, 0, 0}, + {0, 500000000, 1, 0, 500000000}, + {0, 500000000, 2, 1, 0}, + {0, 500000000, 3, 1, 500000000}, + + {1, 0, -3, -3, 0}, + {1, 0, -2, -2, 0}, + {1, 0, -1, -1, 0}, + {1, 0, 0, 0, 0}, + {1, 0, 1, 1, 0}, + {1, 0, 2, 2, 0}, + {1, 0, 3, 3, 0}, + + {2, 0, -3, -6, 0}, + {2, 0, -2, -4, 0}, + {2, 0, -1, -2, 0}, + {2, 0, 0, 0, 0}, + {2, 0, 1, 2, 0}, + {2, 0, 2, 4, 0}, + {2, 0, 3, 6, 0}, + + {3, 0, -3, -9, 0}, + {3, 0, -2, -6, 0}, + {3, 0, -1, -3, 0}, + {3, 0, 0, 0, 0}, + {3, 0, 1, 3, 0}, + {3, 0, 2, 6, 0}, + {3, 0, 3, 9, 0}, + + {3, 333333333, -3, -10, 000000001}, + {3, 333333333, -2, -7, 333333334}, + {3, 333333333, -1, -4, 666666667}, + {3, 333333333, 0, 0, 0}, + {3, 333333333, 1, 3, 333333333}, + {3, 333333333, 2, 6, 666666666}, + {3, 333333333, 3, 9, 999999999}, + }; + } + + @Test(dataProvider="MultipliedBy", groups={"tck"}) + public void multipliedBy(long seconds, int nanos, int multiplicand, long expectedSeconds, int expectedNanos) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.multipliedBy(multiplicand); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanos); + } + + @Test(groups={"tck"}) + public void multipliedBy_max() { + Duration test = Duration.ofSeconds(1); + assertEquals(test.multipliedBy(Long.MAX_VALUE), Duration.ofSeconds(Long.MAX_VALUE)); + } + + @Test(groups={"tck"}) + public void multipliedBy_min() { + Duration test = Duration.ofSeconds(1); + assertEquals(test.multipliedBy(Long.MIN_VALUE), Duration.ofSeconds(Long.MIN_VALUE)); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void multipliedBy_tooBig() { + Duration test = Duration.ofSeconds(1, 1); + test.multipliedBy(Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void multipliedBy_tooBig_negative() { + Duration test = Duration.ofSeconds(1, 1); + test.multipliedBy(Long.MIN_VALUE); + } + + //----------------------------------------------------------------------- + // dividedBy() + //----------------------------------------------------------------------- + @DataProvider(name="DividedBy") + Object[][] provider_dividedBy() { + return new Object[][] { + {-4, 666666667, -3, 1, 111111111}, + {-4, 666666667, -2, 1, 666666666}, + {-4, 666666667, -1, 3, 333333333}, + {-4, 666666667, 1, -4, 666666667}, + {-4, 666666667, 2, -2, 333333334}, + {-4, 666666667, 3, -2, 888888889}, + + {-3, 0, -3, 1, 0}, + {-3, 0, -2, 1, 500000000}, + {-3, 0, -1, 3, 0}, + {-3, 0, 1, -3, 0}, + {-3, 0, 2, -2, 500000000}, + {-3, 0, 3, -1, 0}, + + {-2, 0, -3, 0, 666666666}, + {-2, 0, -2, 1, 0}, + {-2, 0, -1, 2, 0}, + {-2, 0, 1, -2, 0}, + {-2, 0, 2, -1, 0}, + {-2, 0, 3, -1, 333333334}, + + {-1, 0, -3, 0, 333333333}, + {-1, 0, -2, 0, 500000000}, + {-1, 0, -1, 1, 0}, + {-1, 0, 1, -1, 0}, + {-1, 0, 2, -1, 500000000}, + {-1, 0, 3, -1, 666666667}, + + {-1, 500000000, -3, 0, 166666666}, + {-1, 500000000, -2, 0, 250000000}, + {-1, 500000000, -1, 0, 500000000}, + {-1, 500000000, 1, -1, 500000000}, + {-1, 500000000, 2, -1, 750000000}, + {-1, 500000000, 3, -1, 833333334}, + + {0, 0, -3, 0, 0}, + {0, 0, -2, 0, 0}, + {0, 0, -1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 2, 0, 0}, + {0, 0, 3, 0, 0}, + + {0, 500000000, -3, -1, 833333334}, + {0, 500000000, -2, -1, 750000000}, + {0, 500000000, -1, -1, 500000000}, + {0, 500000000, 1, 0, 500000000}, + {0, 500000000, 2, 0, 250000000}, + {0, 500000000, 3, 0, 166666666}, + + {1, 0, -3, -1, 666666667}, + {1, 0, -2, -1, 500000000}, + {1, 0, -1, -1, 0}, + {1, 0, 1, 1, 0}, + {1, 0, 2, 0, 500000000}, + {1, 0, 3, 0, 333333333}, + + {2, 0, -3, -1, 333333334}, + {2, 0, -2, -1, 0}, + {2, 0, -1, -2, 0}, + {2, 0, 1, 2, 0}, + {2, 0, 2, 1, 0}, + {2, 0, 3, 0, 666666666}, + + {3, 0, -3, -1, 0}, + {3, 0, -2, -2, 500000000}, + {3, 0, -1, -3, 0}, + {3, 0, 1, 3, 0}, + {3, 0, 2, 1, 500000000}, + {3, 0, 3, 1, 0}, + + {3, 333333333, -3, -2, 888888889}, + {3, 333333333, -2, -2, 333333334}, + {3, 333333333, -1, -4, 666666667}, + {3, 333333333, 1, 3, 333333333}, + {3, 333333333, 2, 1, 666666666}, + {3, 333333333, 3, 1, 111111111}, + }; + } + + @Test(dataProvider="DividedBy", groups={"tck"}) + public void dividedBy(long seconds, int nanos, int divisor, long expectedSeconds, int expectedNanos) { + Duration t = Duration.ofSeconds(seconds, nanos); + t = t.dividedBy(divisor); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanos); + } + + @Test(dataProvider="DividedBy", expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void dividedByZero(long seconds, int nanos, int divisor, long expectedSeconds, int expectedNanos) { + Duration t = Duration.ofSeconds(seconds, nanos); + t.dividedBy(0); + fail(t + " divided by zero did not throw ArithmeticException"); + } + + @Test(groups={"tck"}) + public void dividedBy_max() { + Duration test = Duration.ofSeconds(Long.MAX_VALUE); + assertEquals(test.dividedBy(Long.MAX_VALUE), Duration.ofSeconds(1)); + } + + //----------------------------------------------------------------------- + // negated() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_negated() { + assertEquals(Duration.ofSeconds(0).negated(), Duration.ofSeconds(0)); + assertEquals(Duration.ofSeconds(12).negated(), Duration.ofSeconds(-12)); + assertEquals(Duration.ofSeconds(-12).negated(), Duration.ofSeconds(12)); + assertEquals(Duration.ofSeconds(12, 20).negated(), Duration.ofSeconds(-12, -20)); + assertEquals(Duration.ofSeconds(12, -20).negated(), Duration.ofSeconds(-12, 20)); + assertEquals(Duration.ofSeconds(-12, -20).negated(), Duration.ofSeconds(12, 20)); + assertEquals(Duration.ofSeconds(-12, 20).negated(), Duration.ofSeconds(12, -20)); + assertEquals(Duration.ofSeconds(Long.MAX_VALUE).negated(), Duration.ofSeconds(-Long.MAX_VALUE)); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_negated_overflow() { + Duration.ofSeconds(Long.MIN_VALUE).negated(); + } + + //----------------------------------------------------------------------- + // abs() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_abs() { + assertEquals(Duration.ofSeconds(0).abs(), Duration.ofSeconds(0)); + assertEquals(Duration.ofSeconds(12).abs(), Duration.ofSeconds(12)); + assertEquals(Duration.ofSeconds(-12).abs(), Duration.ofSeconds(12)); + assertEquals(Duration.ofSeconds(12, 20).abs(), Duration.ofSeconds(12, 20)); + assertEquals(Duration.ofSeconds(12, -20).abs(), Duration.ofSeconds(12, -20)); + assertEquals(Duration.ofSeconds(-12, -20).abs(), Duration.ofSeconds(12, 20)); + assertEquals(Duration.ofSeconds(-12, 20).abs(), Duration.ofSeconds(12, -20)); + assertEquals(Duration.ofSeconds(Long.MAX_VALUE).abs(), Duration.ofSeconds(Long.MAX_VALUE)); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_abs_overflow() { + Duration.ofSeconds(Long.MIN_VALUE).abs(); + } + + //----------------------------------------------------------------------- + // toNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toNanos() { + Duration test = Duration.ofSeconds(321, 123456789); + assertEquals(test.toNanos(), 321123456789L); + } + + @Test(groups={"tck"}) + public void test_toNanos_max() { + Duration test = Duration.ofSeconds(0, Long.MAX_VALUE); + assertEquals(test.toNanos(), Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_toNanos_tooBig() { + Duration test = Duration.ofSeconds(0, Long.MAX_VALUE).plusNanos(1); + test.toNanos(); + } + + //----------------------------------------------------------------------- + // toMillis() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toMillis() { + Duration test = Duration.ofSeconds(321, 123456789); + assertEquals(test.toMillis(), 321000 + 123); + } + + @Test(groups={"tck"}) + public void test_toMillis_max() { + Duration test = Duration.ofSeconds(Long.MAX_VALUE / 1000, (Long.MAX_VALUE % 1000) * 1000000); + assertEquals(test.toMillis(), Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_toMillis_tooBig() { + Duration test = Duration.ofSeconds(Long.MAX_VALUE / 1000, ((Long.MAX_VALUE % 1000) + 1) * 1000000); + test.toMillis(); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + doTest_comparisons_Duration( + Duration.ofSeconds(-2L, 0), + Duration.ofSeconds(-2L, 999999998), + Duration.ofSeconds(-2L, 999999999), + Duration.ofSeconds(-1L, 0), + Duration.ofSeconds(-1L, 1), + Duration.ofSeconds(-1L, 999999998), + Duration.ofSeconds(-1L, 999999999), + Duration.ofSeconds(0L, 0), + Duration.ofSeconds(0L, 1), + Duration.ofSeconds(0L, 2), + Duration.ofSeconds(0L, 999999999), + Duration.ofSeconds(1L, 0), + Duration.ofSeconds(2L, 0) + ); + } + + void doTest_comparisons_Duration(Duration... durations) { + for (int i = 0; i < durations.length; i++) { + Duration a = durations[i]; + for (int j = 0; j < durations.length; j++) { + 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); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + Duration a = Duration.ofSeconds(0L, 0); + 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() { + Comparable c = Duration.ofSeconds(0L); + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + Duration test5a = Duration.ofSeconds(5L, 20); + Duration test5b = Duration.ofSeconds(5L, 20); + Duration test5n = Duration.ofSeconds(5L, 30); + Duration test6 = Duration.ofSeconds(6L, 20); + + assertEquals(test5a.equals(test5a), true); + assertEquals(test5a.equals(test5b), true); + assertEquals(test5a.equals(test5n), false); + assertEquals(test5a.equals(test6), false); + + assertEquals(test5b.equals(test5a), true); + assertEquals(test5b.equals(test5b), true); + assertEquals(test5b.equals(test5n), false); + assertEquals(test5b.equals(test6), false); + + assertEquals(test5n.equals(test5a), false); + assertEquals(test5n.equals(test5b), false); + assertEquals(test5n.equals(test5n), true); + assertEquals(test5n.equals(test6), false); + + assertEquals(test6.equals(test5a), false); + assertEquals(test6.equals(test5b), false); + assertEquals(test6.equals(test5n), false); + assertEquals(test6.equals(test6), true); + } + + @Test(groups={"tck"}) + public void test_equals_null() { + Duration test5 = Duration.ofSeconds(5L, 20); + assertEquals(test5.equals(null), false); + } + + @Test(groups={"tck"}) + public void test_equals_otherClass() { + Duration test5 = Duration.ofSeconds(5L, 20); + assertEquals(test5.equals(""), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_hashCode() { + Duration test5a = Duration.ofSeconds(5L, 20); + Duration test5b = Duration.ofSeconds(5L, 20); + Duration test5n = Duration.ofSeconds(5L, 30); + Duration test6 = Duration.ofSeconds(6L, 20); + + assertEquals(test5a.hashCode() == test5a.hashCode(), true); + assertEquals(test5a.hashCode() == test5b.hashCode(), true); + assertEquals(test5b.hashCode() == test5b.hashCode(), true); + + assertEquals(test5a.hashCode() == test5n.hashCode(), false); + assertEquals(test5a.hashCode() == test6.hashCode(), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="ToString") + Object[][] provider_toString() { + return new Object[][] { + {0, 0, "PT0S"}, + {0, 1, "PT0.000000001S"}, + {0, 10, "PT0.00000001S"}, + {0, 100, "PT0.0000001S"}, + {0, 1000, "PT0.000001S"}, + {0, 10000, "PT0.00001S"}, + {0, 100000, "PT0.0001S"}, + {0, 1000000, "PT0.001S"}, + {0, 10000000, "PT0.01S"}, + {0, 100000000, "PT0.1S"}, + {0, 120000000, "PT0.12S"}, + {0, 123000000, "PT0.123S"}, + {0, 123400000, "PT0.1234S"}, + {0, 123450000, "PT0.12345S"}, + {0, 123456000, "PT0.123456S"}, + {0, 123456700, "PT0.1234567S"}, + {0, 123456780, "PT0.12345678S"}, + {0, 123456789, "PT0.123456789S"}, + {1, 0, "PT1S"}, + {-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"}, + }; + } + + @Test(dataProvider="ToString", groups={"tck"}) + public void test_toString(long seconds, int nanos, String expected) { + Duration t = Duration.ofSeconds(seconds, nanos); + assertEquals(t.toString(), expected); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKInstant.java b/jdk/test/java/time/tck/java/time/TCKInstant.java new file mode 100644 index 00000000000..e1f99d925ed --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKInstant.java @@ -0,0 +1,1680 @@ +/* + * 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) 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; + +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +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.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +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.ZoneOffset; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.JulianFields; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Instant. + */ +@Test +public class TCKInstant extends AbstractDateTimeTest { + + private static final long MIN_SECOND = Instant.MIN.getEpochSecond(); + private static final long MAX_SECOND = Instant.MAX.getEpochSecond(); + + private Instant TEST_12345_123456789; + + @BeforeMethod + public void setUp() { + TEST_12345_123456789 = Instant.ofEpochSecond(12345, 123456789); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_12345_123456789, Instant.MIN, Instant.MAX, Instant.EPOCH}; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + MICRO_OF_SECOND, + MILLI_OF_SECOND, + INSTANT_SECONDS, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Instant.ofEpochMilli(134l)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(2); + dos.writeLong(654321); + dos.writeInt(123456789); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Instant.ofEpochSecond(654321, 123456789), bytes); + } + + //----------------------------------------------------------------------- + private void check(Instant instant, long epochSecs, int nos) { + assertEquals(instant.getEpochSecond(), epochSecs); + assertEquals(instant.getNano(), nos); + assertEquals(instant, instant); + assertEquals(instant.hashCode(), instant.hashCode()); + } + + //----------------------------------------------------------------------- + @Test + public void constant_EPOCH() { + check(Instant.EPOCH, 0, 0); + } + + @Test + public void constant_MIN() { + check(Instant.MIN, -31557014167219200L, 0); + } + + @Test + public void constant_MAX() { + check(Instant.MAX, 31556889864403199L, 999_999_999); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test + public void now() { + Instant expected = Instant.now(Clock.systemUTC()); + Instant test = Instant.now(); + long diff = Math.abs(test.toEpochMilli() - expected.toEpochMilli()); + assertTrue(diff < 100); // less than 0.1 secs + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class) + public void now_Clock_nullClock() { + Instant.now(null); + } + + @Test + public void now_Clock_allSecsInDay_utc() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant expected = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(expected, ZoneOffset.UTC); + Instant test = Instant.now(clock); + assertEquals(test, expected); + } + } + + @Test + public void now_Clock_allSecsInDay_beforeEpoch() { + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant expected = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(expected, ZoneOffset.UTC); + Instant test = Instant.now(clock); + assertEquals(test, expected); + } + } + + //----------------------------------------------------------------------- + // ofEpochSecond(long) + //----------------------------------------------------------------------- + @Test + public void factory_seconds_long() { + for (long i = -2; i <= 2; i++) { + Instant t = Instant.ofEpochSecond(i); + assertEquals(t.getEpochSecond(), i); + assertEquals(t.getNano(), 0); + } + } + + //----------------------------------------------------------------------- + // ofEpochSecond(long,long) + //----------------------------------------------------------------------- + @Test + public void factory_seconds_long_long() { + for (long i = -2; i <= 2; i++) { + for (int j = 0; j < 10; j++) { + Instant t = Instant.ofEpochSecond(i, j); + assertEquals(t.getEpochSecond(), i); + assertEquals(t.getNano(), j); + } + for (int j = -10; j < 0; j++) { + Instant t = Instant.ofEpochSecond(i, j); + assertEquals(t.getEpochSecond(), i - 1); + assertEquals(t.getNano(), j + 1000000000); + } + for (int j = 999999990; j < 1000000000; j++) { + Instant t = Instant.ofEpochSecond(i, j); + assertEquals(t.getEpochSecond(), i); + assertEquals(t.getNano(), j); + } + } + } + + @Test + public void factory_seconds_long_long_nanosNegativeAdjusted() { + Instant test = Instant.ofEpochSecond(2L, -1); + assertEquals(test.getEpochSecond(), 1); + assertEquals(test.getNano(), 999999999); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_seconds_long_long_tooBig() { + Instant.ofEpochSecond(MAX_SECOND, 1000000000); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void factory_seconds_long_long_tooBigBig() { + Instant.ofEpochSecond(Long.MAX_VALUE, Long.MAX_VALUE); + } + + //----------------------------------------------------------------------- + // ofEpochMilli(long) + //----------------------------------------------------------------------- + @DataProvider(name="MillisInstantNoNanos") + Object[][] provider_factory_millis_long() { + return new Object[][] { + {0, 0, 0}, + {1, 0, 1000000}, + {2, 0, 2000000}, + {999, 0, 999000000}, + {1000, 1, 0}, + {1001, 1, 1000000}, + {-1, -1, 999000000}, + {-2, -1, 998000000}, + {-999, -1, 1000000}, + {-1000, -1, 0}, + {-1001, -2, 999000000}, + }; + } + + @Test(dataProvider="MillisInstantNoNanos") + public void factory_millis_long(long millis, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochMilli(millis); + assertEquals(t.getEpochSecond(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + //----------------------------------------------------------------------- + // parse(String) + //----------------------------------------------------------------------- + // see also parse tests under toString() + @DataProvider(name="Parse") + Object[][] provider_factory_parse() { + return new Object[][] { + {"1970-01-01T00:00:00Z", 0, 0}, + {"1970-01-01t00:00:00Z", 0, 0}, + {"1970-01-01T00:00:00z", 0, 0}, + {"1970-01-01T00:00:00.0Z", 0, 0}, + {"1970-01-01T00:00:00.000000000Z", 0, 0}, + + {"1970-01-01T00:00:00.000000001Z", 0, 1}, + {"1970-01-01T00:00:00.100000000Z", 0, 100000000}, + {"1970-01-01T00:00:01Z", 1, 0}, + {"1970-01-01T00:01:00Z", 60, 0}, + {"1970-01-01T00:01:01Z", 61, 0}, + {"1970-01-01T00:01:01.000000001Z", 61, 1}, + {"1970-01-01T01:00:00.000000000Z", 3600, 0}, + {"1970-01-01T01:01:01.000000001Z", 3661, 1}, + {"1970-01-02T01:01:01.100000000Z", 90061, 100000000}, + }; + } + + @Test(dataProvider="Parse") + public void factory_parse(String text, long expectedEpochSeconds, int expectedNanoOfSecond) { + Instant t = Instant.parse(text); + assertEquals(t.getEpochSecond(), expectedEpochSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(dataProvider="Parse") + public void factory_parseLowercase(String text, long expectedEpochSeconds, int expectedNanoOfSecond) { + Instant t = Instant.parse(text.toLowerCase(Locale.ENGLISH)); + assertEquals(t.getEpochSecond(), expectedEpochSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + +// TODO: should comma be accepted? +// @Test(dataProvider="Parse") +// public void factory_parse_comma(String text, long expectedEpochSeconds, int expectedNanoOfSecond) { +// text = text.replace('.', ','); +// Instant t = Instant.parse(text); +// assertEquals(t.getEpochSecond(), expectedEpochSeconds); +// assertEquals(t.getNano(), expectedNanoOfSecond); +// } + + @DataProvider(name="ParseFailures") + Object[][] provider_factory_parseFailures() { + return new Object[][] { + {""}, + {"Z"}, + {"1970-01-01T00:00:00"}, + {"1970-01-01T00:00:0Z"}, + {"1970-01-01T00:00:00.0000000000Z"}, + }; + } + + @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class) + public void factory_parseFailures(String text) { + Instant.parse(text); + } + + @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class) + public void factory_parseFailures_comma(String text) { + text = text.replace('.', ','); + Instant.parse(text); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_parse_nullText() { + Instant.parse(null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + Instant test = TEST_12345_123456789; + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 123456789); + assertEquals(test.get(ChronoField.MICRO_OF_SECOND), 123456); + assertEquals(test.get(ChronoField.MILLI_OF_SECOND), 123); + } + + @Test + public void test_getLong_TemporalField() { + Instant test = TEST_12345_123456789; + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 123456789); + assertEquals(test.getLong(ChronoField.MICRO_OF_SECOND), 123456); + assertEquals(test.getLong(ChronoField.MILLI_OF_SECOND), 123); + assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), 12345); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query_chrono() { + assertEquals(TEST_12345_123456789.query(Queries.chrono()), null); + assertEquals(Queries.chrono().queryFrom(TEST_12345_123456789), null); + } + + @Test + public void test_query_zoneId() { + assertEquals(TEST_12345_123456789.query(Queries.zoneId()), null); + assertEquals(Queries.zoneId().queryFrom(TEST_12345_123456789), null); + } + + @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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_12345_123456789.query(null); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Plus") + Object[][] provider_plus() { + return new Object[][] { + {MIN_SECOND, 0, -MIN_SECOND, 0, 0, 0}, + + {MIN_SECOND, 0, 1, 0, MIN_SECOND + 1, 0}, + {MIN_SECOND, 0, 0, 500, MIN_SECOND, 500}, + {MIN_SECOND, 0, 0, 1000000000, MIN_SECOND + 1, 0}, + + {MIN_SECOND + 1, 0, -1, 0, MIN_SECOND, 0}, + {MIN_SECOND + 1, 0, 0, -500, MIN_SECOND, 999999500}, + {MIN_SECOND + 1, 0, 0, -1000000000, MIN_SECOND, 0}, + + {-4, 666666667, -4, 666666667, -7, 333333334}, + {-4, 666666667, -3, 0, -7, 666666667}, + {-4, 666666667, -2, 0, -6, 666666667}, + {-4, 666666667, -1, 0, -5, 666666667}, + {-4, 666666667, -1, 333333334, -4, 1}, + {-4, 666666667, -1, 666666667, -4, 333333334}, + {-4, 666666667, -1, 999999999, -4, 666666666}, + {-4, 666666667, 0, 0, -4, 666666667}, + {-4, 666666667, 0, 1, -4, 666666668}, + {-4, 666666667, 0, 333333333, -3, 0}, + {-4, 666666667, 0, 666666666, -3, 333333333}, + {-4, 666666667, 1, 0, -3, 666666667}, + {-4, 666666667, 2, 0, -2, 666666667}, + {-4, 666666667, 3, 0, -1, 666666667}, + {-4, 666666667, 3, 333333333, 0, 0}, + + {-3, 0, -4, 666666667, -7, 666666667}, + {-3, 0, -3, 0, -6, 0}, + {-3, 0, -2, 0, -5, 0}, + {-3, 0, -1, 0, -4, 0}, + {-3, 0, -1, 333333334, -4, 333333334}, + {-3, 0, -1, 666666667, -4, 666666667}, + {-3, 0, -1, 999999999, -4, 999999999}, + {-3, 0, 0, 0, -3, 0}, + {-3, 0, 0, 1, -3, 1}, + {-3, 0, 0, 333333333, -3, 333333333}, + {-3, 0, 0, 666666666, -3, 666666666}, + {-3, 0, 1, 0, -2, 0}, + {-3, 0, 2, 0, -1, 0}, + {-3, 0, 3, 0, 0, 0}, + {-3, 0, 3, 333333333, 0, 333333333}, + + {-2, 0, -4, 666666667, -6, 666666667}, + {-2, 0, -3, 0, -5, 0}, + {-2, 0, -2, 0, -4, 0}, + {-2, 0, -1, 0, -3, 0}, + {-2, 0, -1, 333333334, -3, 333333334}, + {-2, 0, -1, 666666667, -3, 666666667}, + {-2, 0, -1, 999999999, -3, 999999999}, + {-2, 0, 0, 0, -2, 0}, + {-2, 0, 0, 1, -2, 1}, + {-2, 0, 0, 333333333, -2, 333333333}, + {-2, 0, 0, 666666666, -2, 666666666}, + {-2, 0, 1, 0, -1, 0}, + {-2, 0, 2, 0, 0, 0}, + {-2, 0, 3, 0, 1, 0}, + {-2, 0, 3, 333333333, 1, 333333333}, + + {-1, 0, -4, 666666667, -5, 666666667}, + {-1, 0, -3, 0, -4, 0}, + {-1, 0, -2, 0, -3, 0}, + {-1, 0, -1, 0, -2, 0}, + {-1, 0, -1, 333333334, -2, 333333334}, + {-1, 0, -1, 666666667, -2, 666666667}, + {-1, 0, -1, 999999999, -2, 999999999}, + {-1, 0, 0, 0, -1, 0}, + {-1, 0, 0, 1, -1, 1}, + {-1, 0, 0, 333333333, -1, 333333333}, + {-1, 0, 0, 666666666, -1, 666666666}, + {-1, 0, 1, 0, 0, 0}, + {-1, 0, 2, 0, 1, 0}, + {-1, 0, 3, 0, 2, 0}, + {-1, 0, 3, 333333333, 2, 333333333}, + + {-1, 666666667, -4, 666666667, -4, 333333334}, + {-1, 666666667, -3, 0, -4, 666666667}, + {-1, 666666667, -2, 0, -3, 666666667}, + {-1, 666666667, -1, 0, -2, 666666667}, + {-1, 666666667, -1, 333333334, -1, 1}, + {-1, 666666667, -1, 666666667, -1, 333333334}, + {-1, 666666667, -1, 999999999, -1, 666666666}, + {-1, 666666667, 0, 0, -1, 666666667}, + {-1, 666666667, 0, 1, -1, 666666668}, + {-1, 666666667, 0, 333333333, 0, 0}, + {-1, 666666667, 0, 666666666, 0, 333333333}, + {-1, 666666667, 1, 0, 0, 666666667}, + {-1, 666666667, 2, 0, 1, 666666667}, + {-1, 666666667, 3, 0, 2, 666666667}, + {-1, 666666667, 3, 333333333, 3, 0}, + + {0, 0, -4, 666666667, -4, 666666667}, + {0, 0, -3, 0, -3, 0}, + {0, 0, -2, 0, -2, 0}, + {0, 0, -1, 0, -1, 0}, + {0, 0, -1, 333333334, -1, 333333334}, + {0, 0, -1, 666666667, -1, 666666667}, + {0, 0, -1, 999999999, -1, 999999999}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 1}, + {0, 0, 0, 333333333, 0, 333333333}, + {0, 0, 0, 666666666, 0, 666666666}, + {0, 0, 1, 0, 1, 0}, + {0, 0, 2, 0, 2, 0}, + {0, 0, 3, 0, 3, 0}, + {0, 0, 3, 333333333, 3, 333333333}, + + {0, 333333333, -4, 666666667, -3, 0}, + {0, 333333333, -3, 0, -3, 333333333}, + {0, 333333333, -2, 0, -2, 333333333}, + {0, 333333333, -1, 0, -1, 333333333}, + {0, 333333333, -1, 333333334, -1, 666666667}, + {0, 333333333, -1, 666666667, 0, 0}, + {0, 333333333, -1, 999999999, 0, 333333332}, + {0, 333333333, 0, 0, 0, 333333333}, + {0, 333333333, 0, 1, 0, 333333334}, + {0, 333333333, 0, 333333333, 0, 666666666}, + {0, 333333333, 0, 666666666, 0, 999999999}, + {0, 333333333, 1, 0, 1, 333333333}, + {0, 333333333, 2, 0, 2, 333333333}, + {0, 333333333, 3, 0, 3, 333333333}, + {0, 333333333, 3, 333333333, 3, 666666666}, + + {1, 0, -4, 666666667, -3, 666666667}, + {1, 0, -3, 0, -2, 0}, + {1, 0, -2, 0, -1, 0}, + {1, 0, -1, 0, 0, 0}, + {1, 0, -1, 333333334, 0, 333333334}, + {1, 0, -1, 666666667, 0, 666666667}, + {1, 0, -1, 999999999, 0, 999999999}, + {1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 1, 1}, + {1, 0, 0, 333333333, 1, 333333333}, + {1, 0, 0, 666666666, 1, 666666666}, + {1, 0, 1, 0, 2, 0}, + {1, 0, 2, 0, 3, 0}, + {1, 0, 3, 0, 4, 0}, + {1, 0, 3, 333333333, 4, 333333333}, + + {2, 0, -4, 666666667, -2, 666666667}, + {2, 0, -3, 0, -1, 0}, + {2, 0, -2, 0, 0, 0}, + {2, 0, -1, 0, 1, 0}, + {2, 0, -1, 333333334, 1, 333333334}, + {2, 0, -1, 666666667, 1, 666666667}, + {2, 0, -1, 999999999, 1, 999999999}, + {2, 0, 0, 0, 2, 0}, + {2, 0, 0, 1, 2, 1}, + {2, 0, 0, 333333333, 2, 333333333}, + {2, 0, 0, 666666666, 2, 666666666}, + {2, 0, 1, 0, 3, 0}, + {2, 0, 2, 0, 4, 0}, + {2, 0, 3, 0, 5, 0}, + {2, 0, 3, 333333333, 5, 333333333}, + + {3, 0, -4, 666666667, -1, 666666667}, + {3, 0, -3, 0, 0, 0}, + {3, 0, -2, 0, 1, 0}, + {3, 0, -1, 0, 2, 0}, + {3, 0, -1, 333333334, 2, 333333334}, + {3, 0, -1, 666666667, 2, 666666667}, + {3, 0, -1, 999999999, 2, 999999999}, + {3, 0, 0, 0, 3, 0}, + {3, 0, 0, 1, 3, 1}, + {3, 0, 0, 333333333, 3, 333333333}, + {3, 0, 0, 666666666, 3, 666666666}, + {3, 0, 1, 0, 4, 0}, + {3, 0, 2, 0, 5, 0}, + {3, 0, 3, 0, 6, 0}, + {3, 0, 3, 333333333, 6, 333333333}, + + {3, 333333333, -4, 666666667, 0, 0}, + {3, 333333333, -3, 0, 0, 333333333}, + {3, 333333333, -2, 0, 1, 333333333}, + {3, 333333333, -1, 0, 2, 333333333}, + {3, 333333333, -1, 333333334, 2, 666666667}, + {3, 333333333, -1, 666666667, 3, 0}, + {3, 333333333, -1, 999999999, 3, 333333332}, + {3, 333333333, 0, 0, 3, 333333333}, + {3, 333333333, 0, 1, 3, 333333334}, + {3, 333333333, 0, 333333333, 3, 666666666}, + {3, 333333333, 0, 666666666, 3, 999999999}, + {3, 333333333, 1, 0, 4, 333333333}, + {3, 333333333, 2, 0, 5, 333333333}, + {3, 333333333, 3, 0, 6, 333333333}, + {3, 333333333, 3, 333333333, 6, 666666666}, + + {MAX_SECOND - 1, 0, 1, 0, MAX_SECOND, 0}, + {MAX_SECOND - 1, 0, 0, 500, MAX_SECOND - 1, 500}, + {MAX_SECOND - 1, 0, 0, 1000000000, MAX_SECOND, 0}, + + {MAX_SECOND, 0, -1, 0, MAX_SECOND - 1, 0}, + {MAX_SECOND, 0, 0, -500, MAX_SECOND - 1, 999999500}, + {MAX_SECOND, 0, 0, -1000000000, MAX_SECOND - 1, 0}, + + {MAX_SECOND, 0, -MAX_SECOND, 0, 0, 0}, + }; + } + + @Test(dataProvider="Plus") + public void plus_Duration(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos).plus(Duration.ofSeconds(otherSeconds, otherNanos)); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plus_Duration_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999); + i.plus(Duration.ofSeconds(0, 1)); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plus_Duration_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND); + i.plus(Duration.ofSeconds(-1, 999999999)); + } + + //-----------------------------------------------------------------------a + @Test(dataProvider="Plus") + public void plus_longTemporalUnit(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos).plus(otherSeconds, SECONDS).plus(otherNanos, NANOS); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plus_longTemporalUnit_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999); + i.plus(1, NANOS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plus_longTemporalUnit_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND); + i.plus(999999999, NANOS); + i.plus(-1, SECONDS); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusSeconds") + Object[][] provider_plusSeconds_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 1, 0}, + {0, 0, -1, -1, 0}, + {0, 0, MAX_SECOND, MAX_SECOND, 0}, + {0, 0, MIN_SECOND, MIN_SECOND, 0}, + {1, 0, 0, 1, 0}, + {1, 0, 1, 2, 0}, + {1, 0, -1, 0, 0}, + {1, 0, MAX_SECOND - 1, MAX_SECOND, 0}, + {1, 0, MIN_SECOND, MIN_SECOND + 1, 0}, + {1, 1, 0, 1, 1}, + {1, 1, 1, 2, 1}, + {1, 1, -1, 0, 1}, + {1, 1, MAX_SECOND - 1, MAX_SECOND, 1}, + {1, 1, MIN_SECOND, MIN_SECOND + 1, 1}, + {-1, 1, 0, -1, 1}, + {-1, 1, 1, 0, 1}, + {-1, 1, -1, -2, 1}, + {-1, 1, MAX_SECOND, MAX_SECOND - 1, 1}, + {-1, 1, MIN_SECOND + 1, MIN_SECOND, 1}, + + {MAX_SECOND, 2, -MAX_SECOND, 0, 2}, + {MIN_SECOND, 2, -MIN_SECOND, 0, 2}, + }; + } + + @Test(dataProvider="PlusSeconds") + public void plusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochSecond(seconds, nanos); + t = t.plusSeconds(amount); + assertEquals(t.getEpochSecond(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void plusSeconds_long_overflowTooBig() { + Instant t = Instant.ofEpochSecond(1, 0); + t.plusSeconds(Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void plusSeconds_long_overflowTooSmall() { + Instant t = Instant.ofEpochSecond(-1, 0); + t.plusSeconds(Long.MIN_VALUE); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusMillis") + Object[][] provider_plusMillis_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1000000}, + {0, 0, 999, 0, 999000000}, + {0, 0, 1000, 1, 0}, + {0, 0, 1001, 1, 1000000}, + {0, 0, 1999, 1, 999000000}, + {0, 0, 2000, 2, 0}, + {0, 0, -1, -1, 999000000}, + {0, 0, -999, -1, 1000000}, + {0, 0, -1000, -1, 0}, + {0, 0, -1001, -2, 999000000}, + {0, 0, -1999, -2, 1000000}, + + {0, 1, 0, 0, 1}, + {0, 1, 1, 0, 1000001}, + {0, 1, 998, 0, 998000001}, + {0, 1, 999, 0, 999000001}, + {0, 1, 1000, 1, 1}, + {0, 1, 1998, 1, 998000001}, + {0, 1, 1999, 1, 999000001}, + {0, 1, 2000, 2, 1}, + {0, 1, -1, -1, 999000001}, + {0, 1, -2, -1, 998000001}, + {0, 1, -1000, -1, 1}, + {0, 1, -1001, -2, 999000001}, + + {0, 1000000, 0, 0, 1000000}, + {0, 1000000, 1, 0, 2000000}, + {0, 1000000, 998, 0, 999000000}, + {0, 1000000, 999, 1, 0}, + {0, 1000000, 1000, 1, 1000000}, + {0, 1000000, 1998, 1, 999000000}, + {0, 1000000, 1999, 2, 0}, + {0, 1000000, 2000, 2, 1000000}, + {0, 1000000, -1, 0, 0}, + {0, 1000000, -2, -1, 999000000}, + {0, 1000000, -999, -1, 2000000}, + {0, 1000000, -1000, -1, 1000000}, + {0, 1000000, -1001, -1, 0}, + {0, 1000000, -1002, -2, 999000000}, + + {0, 999999999, 0, 0, 999999999}, + {0, 999999999, 1, 1, 999999}, + {0, 999999999, 999, 1, 998999999}, + {0, 999999999, 1000, 1, 999999999}, + {0, 999999999, 1001, 2, 999999}, + {0, 999999999, -1, 0, 998999999}, + {0, 999999999, -1000, -1, 999999999}, + {0, 999999999, -1001, -1, 998999999}, + + {0, 0, Long.MAX_VALUE, Long.MAX_VALUE / 1000, (int) (Long.MAX_VALUE % 1000) * 1000000}, + {0, 0, Long.MIN_VALUE, Long.MIN_VALUE / 1000 - 1, (int) (Long.MIN_VALUE % 1000) * 1000000 + 1000000000}, + }; + } + + @Test(dataProvider="PlusMillis") + public void plusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochSecond(seconds, nanos); + t = t.plusMillis(amount); + assertEquals(t.getEpochSecond(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="PlusMillis") + public void plusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochSecond(seconds + 1, nanos); + t = t.plusMillis(amount); + assertEquals(t.getEpochSecond(), expectedSeconds + 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + @Test(dataProvider="PlusMillis") + public void plusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochSecond(seconds - 1, nanos); + t = t.plusMillis(amount); + assertEquals(t.getEpochSecond(), expectedSeconds - 1); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test + public void plusMillis_long_max() { + Instant t = Instant.ofEpochSecond(MAX_SECOND, 998999999); + t = t.plusMillis(1); + assertEquals(t.getEpochSecond(), MAX_SECOND); + assertEquals(t.getNano(), 999999999); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plusMillis_long_overflowTooBig() { + Instant t = Instant.ofEpochSecond(MAX_SECOND, 999000000); + t.plusMillis(1); + } + + @Test + public void plusMillis_long_min() { + Instant t = Instant.ofEpochSecond(MIN_SECOND, 1000000); + t = t.plusMillis(-1); + assertEquals(t.getEpochSecond(), MIN_SECOND); + assertEquals(t.getNano(), 0); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plusMillis_long_overflowTooSmall() { + Instant t = Instant.ofEpochSecond(MIN_SECOND, 0); + t.plusMillis(-1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="PlusNanos") + Object[][] provider_plusNanos_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1}, + {0, 0, 999999999, 0, 999999999}, + {0, 0, 1000000000, 1, 0}, + {0, 0, 1000000001, 1, 1}, + {0, 0, 1999999999, 1, 999999999}, + {0, 0, 2000000000, 2, 0}, + {0, 0, -1, -1, 999999999}, + {0, 0, -999999999, -1, 1}, + {0, 0, -1000000000, -1, 0}, + {0, 0, -1000000001, -2, 999999999}, + {0, 0, -1999999999, -2, 1}, + + {1, 0, 0, 1, 0}, + {1, 0, 1, 1, 1}, + {1, 0, 999999999, 1, 999999999}, + {1, 0, 1000000000, 2, 0}, + {1, 0, 1000000001, 2, 1}, + {1, 0, 1999999999, 2, 999999999}, + {1, 0, 2000000000, 3, 0}, + {1, 0, -1, 0, 999999999}, + {1, 0, -999999999, 0, 1}, + {1, 0, -1000000000, 0, 0}, + {1, 0, -1000000001, -1, 999999999}, + {1, 0, -1999999999, -1, 1}, + + {-1, 0, 0, -1, 0}, + {-1, 0, 1, -1, 1}, + {-1, 0, 999999999, -1, 999999999}, + {-1, 0, 1000000000, 0, 0}, + {-1, 0, 1000000001, 0, 1}, + {-1, 0, 1999999999, 0, 999999999}, + {-1, 0, 2000000000, 1, 0}, + {-1, 0, -1, -2, 999999999}, + {-1, 0, -999999999, -2, 1}, + {-1, 0, -1000000000, -2, 0}, + {-1, 0, -1000000001, -3, 999999999}, + {-1, 0, -1999999999, -3, 1}, + + {1, 1, 0, 1, 1}, + {1, 1, 1, 1, 2}, + {1, 1, 999999998, 1, 999999999}, + {1, 1, 999999999, 2, 0}, + {1, 1, 1000000000, 2, 1}, + {1, 1, 1999999998, 2, 999999999}, + {1, 1, 1999999999, 3, 0}, + {1, 1, 2000000000, 3, 1}, + {1, 1, -1, 1, 0}, + {1, 1, -2, 0, 999999999}, + {1, 1, -1000000000, 0, 1}, + {1, 1, -1000000001, 0, 0}, + {1, 1, -1000000002, -1, 999999999}, + {1, 1, -2000000000, -1, 1}, + + {1, 999999999, 0, 1, 999999999}, + {1, 999999999, 1, 2, 0}, + {1, 999999999, 999999999, 2, 999999998}, + {1, 999999999, 1000000000, 2, 999999999}, + {1, 999999999, 1000000001, 3, 0}, + {1, 999999999, -1, 1, 999999998}, + {1, 999999999, -1000000000, 0, 999999999}, + {1, 999999999, -1000000001, 0, 999999998}, + {1, 999999999, -1999999999, 0, 0}, + {1, 999999999, -2000000000, -1, 999999999}, + + {MAX_SECOND, 0, 999999999, MAX_SECOND, 999999999}, + {MAX_SECOND - 1, 0, 1999999999, MAX_SECOND, 999999999}, + {MIN_SECOND, 1, -1, MIN_SECOND, 0}, + {MIN_SECOND + 1, 1, -1000000001, MIN_SECOND, 0}, + + {0, 0, MAX_SECOND, MAX_SECOND / 1000000000, (int) (MAX_SECOND % 1000000000)}, + {0, 0, MIN_SECOND, MIN_SECOND / 1000000000 - 1, (int) (MIN_SECOND % 1000000000) + 1000000000}, + }; + } + + @Test(dataProvider="PlusNanos") + public void plusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant t = Instant.ofEpochSecond(seconds, nanos); + t = t.plusNanos(amount); + assertEquals(t.getEpochSecond(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plusNanos_long_overflowTooBig() { + Instant t = Instant.ofEpochSecond(MAX_SECOND, 999999999); + t.plusNanos(1); + } + + @Test(expectedExceptions=DateTimeException.class) + public void plusNanos_long_overflowTooSmall() { + Instant t = Instant.ofEpochSecond(MIN_SECOND, 0); + t.plusNanos(-1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Minus") + Object[][] provider_minus() { + return new Object[][] { + {MIN_SECOND, 0, MIN_SECOND, 0, 0, 0}, + + {MIN_SECOND, 0, -1, 0, MIN_SECOND + 1, 0}, + {MIN_SECOND, 0, 0, -500, MIN_SECOND, 500}, + {MIN_SECOND, 0, 0, -1000000000, MIN_SECOND + 1, 0}, + + {MIN_SECOND + 1, 0, 1, 0, MIN_SECOND, 0}, + {MIN_SECOND + 1, 0, 0, 500, MIN_SECOND, 999999500}, + {MIN_SECOND + 1, 0, 0, 1000000000, MIN_SECOND, 0}, + + {-4, 666666667, -4, 666666667, 0, 0}, + {-4, 666666667, -3, 0, -1, 666666667}, + {-4, 666666667, -2, 0, -2, 666666667}, + {-4, 666666667, -1, 0, -3, 666666667}, + {-4, 666666667, -1, 333333334, -3, 333333333}, + {-4, 666666667, -1, 666666667, -3, 0}, + {-4, 666666667, -1, 999999999, -4, 666666668}, + {-4, 666666667, 0, 0, -4, 666666667}, + {-4, 666666667, 0, 1, -4, 666666666}, + {-4, 666666667, 0, 333333333, -4, 333333334}, + {-4, 666666667, 0, 666666666, -4, 1}, + {-4, 666666667, 1, 0, -5, 666666667}, + {-4, 666666667, 2, 0, -6, 666666667}, + {-4, 666666667, 3, 0, -7, 666666667}, + {-4, 666666667, 3, 333333333, -7, 333333334}, + + {-3, 0, -4, 666666667, 0, 333333333}, + {-3, 0, -3, 0, 0, 0}, + {-3, 0, -2, 0, -1, 0}, + {-3, 0, -1, 0, -2, 0}, + {-3, 0, -1, 333333334, -3, 666666666}, + {-3, 0, -1, 666666667, -3, 333333333}, + {-3, 0, -1, 999999999, -3, 1}, + {-3, 0, 0, 0, -3, 0}, + {-3, 0, 0, 1, -4, 999999999}, + {-3, 0, 0, 333333333, -4, 666666667}, + {-3, 0, 0, 666666666, -4, 333333334}, + {-3, 0, 1, 0, -4, 0}, + {-3, 0, 2, 0, -5, 0}, + {-3, 0, 3, 0, -6, 0}, + {-3, 0, 3, 333333333, -7, 666666667}, + + {-2, 0, -4, 666666667, 1, 333333333}, + {-2, 0, -3, 0, 1, 0}, + {-2, 0, -2, 0, 0, 0}, + {-2, 0, -1, 0, -1, 0}, + {-2, 0, -1, 333333334, -2, 666666666}, + {-2, 0, -1, 666666667, -2, 333333333}, + {-2, 0, -1, 999999999, -2, 1}, + {-2, 0, 0, 0, -2, 0}, + {-2, 0, 0, 1, -3, 999999999}, + {-2, 0, 0, 333333333, -3, 666666667}, + {-2, 0, 0, 666666666, -3, 333333334}, + {-2, 0, 1, 0, -3, 0}, + {-2, 0, 2, 0, -4, 0}, + {-2, 0, 3, 0, -5, 0}, + {-2, 0, 3, 333333333, -6, 666666667}, + + {-1, 0, -4, 666666667, 2, 333333333}, + {-1, 0, -3, 0, 2, 0}, + {-1, 0, -2, 0, 1, 0}, + {-1, 0, -1, 0, 0, 0}, + {-1, 0, -1, 333333334, -1, 666666666}, + {-1, 0, -1, 666666667, -1, 333333333}, + {-1, 0, -1, 999999999, -1, 1}, + {-1, 0, 0, 0, -1, 0}, + {-1, 0, 0, 1, -2, 999999999}, + {-1, 0, 0, 333333333, -2, 666666667}, + {-1, 0, 0, 666666666, -2, 333333334}, + {-1, 0, 1, 0, -2, 0}, + {-1, 0, 2, 0, -3, 0}, + {-1, 0, 3, 0, -4, 0}, + {-1, 0, 3, 333333333, -5, 666666667}, + + {-1, 666666667, -4, 666666667, 3, 0}, + {-1, 666666667, -3, 0, 2, 666666667}, + {-1, 666666667, -2, 0, 1, 666666667}, + {-1, 666666667, -1, 0, 0, 666666667}, + {-1, 666666667, -1, 333333334, 0, 333333333}, + {-1, 666666667, -1, 666666667, 0, 0}, + {-1, 666666667, -1, 999999999, -1, 666666668}, + {-1, 666666667, 0, 0, -1, 666666667}, + {-1, 666666667, 0, 1, -1, 666666666}, + {-1, 666666667, 0, 333333333, -1, 333333334}, + {-1, 666666667, 0, 666666666, -1, 1}, + {-1, 666666667, 1, 0, -2, 666666667}, + {-1, 666666667, 2, 0, -3, 666666667}, + {-1, 666666667, 3, 0, -4, 666666667}, + {-1, 666666667, 3, 333333333, -4, 333333334}, + + {0, 0, -4, 666666667, 3, 333333333}, + {0, 0, -3, 0, 3, 0}, + {0, 0, -2, 0, 2, 0}, + {0, 0, -1, 0, 1, 0}, + {0, 0, -1, 333333334, 0, 666666666}, + {0, 0, -1, 666666667, 0, 333333333}, + {0, 0, -1, 999999999, 0, 1}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, -1, 999999999}, + {0, 0, 0, 333333333, -1, 666666667}, + {0, 0, 0, 666666666, -1, 333333334}, + {0, 0, 1, 0, -1, 0}, + {0, 0, 2, 0, -2, 0}, + {0, 0, 3, 0, -3, 0}, + {0, 0, 3, 333333333, -4, 666666667}, + + {0, 333333333, -4, 666666667, 3, 666666666}, + {0, 333333333, -3, 0, 3, 333333333}, + {0, 333333333, -2, 0, 2, 333333333}, + {0, 333333333, -1, 0, 1, 333333333}, + {0, 333333333, -1, 333333334, 0, 999999999}, + {0, 333333333, -1, 666666667, 0, 666666666}, + {0, 333333333, -1, 999999999, 0, 333333334}, + {0, 333333333, 0, 0, 0, 333333333}, + {0, 333333333, 0, 1, 0, 333333332}, + {0, 333333333, 0, 333333333, 0, 0}, + {0, 333333333, 0, 666666666, -1, 666666667}, + {0, 333333333, 1, 0, -1, 333333333}, + {0, 333333333, 2, 0, -2, 333333333}, + {0, 333333333, 3, 0, -3, 333333333}, + {0, 333333333, 3, 333333333, -3, 0}, + + {1, 0, -4, 666666667, 4, 333333333}, + {1, 0, -3, 0, 4, 0}, + {1, 0, -2, 0, 3, 0}, + {1, 0, -1, 0, 2, 0}, + {1, 0, -1, 333333334, 1, 666666666}, + {1, 0, -1, 666666667, 1, 333333333}, + {1, 0, -1, 999999999, 1, 1}, + {1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 999999999}, + {1, 0, 0, 333333333, 0, 666666667}, + {1, 0, 0, 666666666, 0, 333333334}, + {1, 0, 1, 0, 0, 0}, + {1, 0, 2, 0, -1, 0}, + {1, 0, 3, 0, -2, 0}, + {1, 0, 3, 333333333, -3, 666666667}, + + {2, 0, -4, 666666667, 5, 333333333}, + {2, 0, -3, 0, 5, 0}, + {2, 0, -2, 0, 4, 0}, + {2, 0, -1, 0, 3, 0}, + {2, 0, -1, 333333334, 2, 666666666}, + {2, 0, -1, 666666667, 2, 333333333}, + {2, 0, -1, 999999999, 2, 1}, + {2, 0, 0, 0, 2, 0}, + {2, 0, 0, 1, 1, 999999999}, + {2, 0, 0, 333333333, 1, 666666667}, + {2, 0, 0, 666666666, 1, 333333334}, + {2, 0, 1, 0, 1, 0}, + {2, 0, 2, 0, 0, 0}, + {2, 0, 3, 0, -1, 0}, + {2, 0, 3, 333333333, -2, 666666667}, + + {3, 0, -4, 666666667, 6, 333333333}, + {3, 0, -3, 0, 6, 0}, + {3, 0, -2, 0, 5, 0}, + {3, 0, -1, 0, 4, 0}, + {3, 0, -1, 333333334, 3, 666666666}, + {3, 0, -1, 666666667, 3, 333333333}, + {3, 0, -1, 999999999, 3, 1}, + {3, 0, 0, 0, 3, 0}, + {3, 0, 0, 1, 2, 999999999}, + {3, 0, 0, 333333333, 2, 666666667}, + {3, 0, 0, 666666666, 2, 333333334}, + {3, 0, 1, 0, 2, 0}, + {3, 0, 2, 0, 1, 0}, + {3, 0, 3, 0, 0, 0}, + {3, 0, 3, 333333333, -1, 666666667}, + + {3, 333333333, -4, 666666667, 6, 666666666}, + {3, 333333333, -3, 0, 6, 333333333}, + {3, 333333333, -2, 0, 5, 333333333}, + {3, 333333333, -1, 0, 4, 333333333}, + {3, 333333333, -1, 333333334, 3, 999999999}, + {3, 333333333, -1, 666666667, 3, 666666666}, + {3, 333333333, -1, 999999999, 3, 333333334}, + {3, 333333333, 0, 0, 3, 333333333}, + {3, 333333333, 0, 1, 3, 333333332}, + {3, 333333333, 0, 333333333, 3, 0}, + {3, 333333333, 0, 666666666, 2, 666666667}, + {3, 333333333, 1, 0, 2, 333333333}, + {3, 333333333, 2, 0, 1, 333333333}, + {3, 333333333, 3, 0, 0, 333333333}, + {3, 333333333, 3, 333333333, 0, 0}, + + {MAX_SECOND - 1, 0, -1, 0, MAX_SECOND, 0}, + {MAX_SECOND - 1, 0, 0, -500, MAX_SECOND - 1, 500}, + {MAX_SECOND - 1, 0, 0, -1000000000, MAX_SECOND, 0}, + + {MAX_SECOND, 0, 1, 0, MAX_SECOND - 1, 0}, + {MAX_SECOND, 0, 0, 500, MAX_SECOND - 1, 999999500}, + {MAX_SECOND, 0, 0, 1000000000, MAX_SECOND - 1, 0}, + + {MAX_SECOND, 0, MAX_SECOND, 0, 0, 0}, + }; + } + + @Test(dataProvider="Minus") + public void minus_Duration(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos).minus(Duration.ofSeconds(otherSeconds, otherNanos)); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minus_Duration_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND); + i.minus(Duration.ofSeconds(0, 1)); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minus_Duration_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999); + i.minus(Duration.ofSeconds(-1, 999999999)); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="Minus") + public void minus_longTemporalUnit(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos).minus(otherSeconds, SECONDS).minus(otherNanos, NANOS); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minus_longTemporalUnit_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND); + i.minus(1, NANOS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minus_longTemporalUnit_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999); + i.minus(999999999, NANOS); + i.minus(-1, SECONDS); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusSeconds") + Object[][] provider_minusSeconds_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 0}, + {0, 0, -1, 1, 0}, + {0, 0, -MIN_SECOND, MIN_SECOND, 0}, + {1, 0, 0, 1, 0}, + {1, 0, 1, 0, 0}, + {1, 0, -1, 2, 0}, + {1, 0, -MIN_SECOND + 1, MIN_SECOND, 0}, + {1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1}, + {1, 1, -1, 2, 1}, + {1, 1, -MIN_SECOND, MIN_SECOND + 1, 1}, + {1, 1, -MIN_SECOND + 1, MIN_SECOND, 1}, + {-1, 1, 0, -1, 1}, + {-1, 1, 1, -2, 1}, + {-1, 1, -1, 0, 1}, + {-1, 1, -MAX_SECOND, MAX_SECOND - 1, 1}, + {-1, 1, -(MAX_SECOND + 1), MAX_SECOND, 1}, + + {MIN_SECOND, 2, MIN_SECOND, 0, 2}, + {MIN_SECOND + 1, 2, MIN_SECOND, 1, 2}, + {MAX_SECOND - 1, 2, MAX_SECOND, -1, 2}, + {MAX_SECOND, 2, MAX_SECOND, 0, 2}, + }; + } + + @Test(dataProvider="MinusSeconds") + public void minusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos); + i = i.minusSeconds(amount); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions = {ArithmeticException.class}) + public void minusSeconds_long_overflowTooBig() { + Instant i = Instant.ofEpochSecond(1, 0); + i.minusSeconds(Long.MIN_VALUE + 1); + } + + @Test(expectedExceptions = {ArithmeticException.class}) + public void minusSeconds_long_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(-2, 0); + i.minusSeconds(Long.MAX_VALUE); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusMillis") + Object[][] provider_minusMillis_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 999000000}, + {0, 0, 999, -1, 1000000}, + {0, 0, 1000, -1, 0}, + {0, 0, 1001, -2, 999000000}, + {0, 0, 1999, -2, 1000000}, + {0, 0, 2000, -2, 0}, + {0, 0, -1, 0, 1000000}, + {0, 0, -999, 0, 999000000}, + {0, 0, -1000, 1, 0}, + {0, 0, -1001, 1, 1000000}, + {0, 0, -1999, 1, 999000000}, + + {0, 1, 0, 0, 1}, + {0, 1, 1, -1, 999000001}, + {0, 1, 998, -1, 2000001}, + {0, 1, 999, -1, 1000001}, + {0, 1, 1000, -1, 1}, + {0, 1, 1998, -2, 2000001}, + {0, 1, 1999, -2, 1000001}, + {0, 1, 2000, -2, 1}, + {0, 1, -1, 0, 1000001}, + {0, 1, -2, 0, 2000001}, + {0, 1, -1000, 1, 1}, + {0, 1, -1001, 1, 1000001}, + + {0, 1000000, 0, 0, 1000000}, + {0, 1000000, 1, 0, 0}, + {0, 1000000, 998, -1, 3000000}, + {0, 1000000, 999, -1, 2000000}, + {0, 1000000, 1000, -1, 1000000}, + {0, 1000000, 1998, -2, 3000000}, + {0, 1000000, 1999, -2, 2000000}, + {0, 1000000, 2000, -2, 1000000}, + {0, 1000000, -1, 0, 2000000}, + {0, 1000000, -2, 0, 3000000}, + {0, 1000000, -999, 1, 0}, + {0, 1000000, -1000, 1, 1000000}, + {0, 1000000, -1001, 1, 2000000}, + {0, 1000000, -1002, 1, 3000000}, + + {0, 999999999, 0, 0, 999999999}, + {0, 999999999, 1, 0, 998999999}, + {0, 999999999, 999, 0, 999999}, + {0, 999999999, 1000, -1, 999999999}, + {0, 999999999, 1001, -1, 998999999}, + {0, 999999999, -1, 1, 999999}, + {0, 999999999, -1000, 1, 999999999}, + {0, 999999999, -1001, 2, 999999}, + + {0, 0, Long.MAX_VALUE, -(Long.MAX_VALUE / 1000) - 1, (int) -(Long.MAX_VALUE % 1000) * 1000000 + 1000000000}, + {0, 0, Long.MIN_VALUE, -(Long.MIN_VALUE / 1000), (int) -(Long.MIN_VALUE % 1000) * 1000000}, + }; + } + + @Test(dataProvider="MinusMillis") + public void minusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos); + i = i.minusMillis(amount); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(dataProvider="MinusMillis") + public void minusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds + 1, nanos); + i = i.minusMillis(amount); + assertEquals(i.getEpochSecond(), expectedSeconds + 1); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(dataProvider="MinusMillis") + public void minusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds - 1, nanos); + i = i.minusMillis(amount); + assertEquals(i.getEpochSecond(), expectedSeconds - 1); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test + public void minusMillis_long_max() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 998999999); + i = i.minusMillis(-1); + assertEquals(i.getEpochSecond(), MAX_SECOND); + assertEquals(i.getNano(), 999999999); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minusMillis_long_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999000000); + i.minusMillis(-1); + } + + @Test + public void minusMillis_long_min() { + Instant i = Instant.ofEpochSecond(MIN_SECOND, 1000000); + i = i.minusMillis(1); + assertEquals(i.getEpochSecond(), MIN_SECOND); + assertEquals(i.getNano(), 0); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minusMillis_long_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND, 0); + i.minusMillis(1); + } + + //----------------------------------------------------------------------- + @DataProvider(name="MinusNanos") + Object[][] provider_minusNanos_long() { + return new Object[][] { + {0, 0, 0, 0, 0}, + {0, 0, 1, -1, 999999999}, + {0, 0, 999999999, -1, 1}, + {0, 0, 1000000000, -1, 0}, + {0, 0, 1000000001, -2, 999999999}, + {0, 0, 1999999999, -2, 1}, + {0, 0, 2000000000, -2, 0}, + {0, 0, -1, 0, 1}, + {0, 0, -999999999, 0, 999999999}, + {0, 0, -1000000000, 1, 0}, + {0, 0, -1000000001, 1, 1}, + {0, 0, -1999999999, 1, 999999999}, + + {1, 0, 0, 1, 0}, + {1, 0, 1, 0, 999999999}, + {1, 0, 999999999, 0, 1}, + {1, 0, 1000000000, 0, 0}, + {1, 0, 1000000001, -1, 999999999}, + {1, 0, 1999999999, -1, 1}, + {1, 0, 2000000000, -1, 0}, + {1, 0, -1, 1, 1}, + {1, 0, -999999999, 1, 999999999}, + {1, 0, -1000000000, 2, 0}, + {1, 0, -1000000001, 2, 1}, + {1, 0, -1999999999, 2, 999999999}, + + {-1, 0, 0, -1, 0}, + {-1, 0, 1, -2, 999999999}, + {-1, 0, 999999999, -2, 1}, + {-1, 0, 1000000000, -2, 0}, + {-1, 0, 1000000001, -3, 999999999}, + {-1, 0, 1999999999, -3, 1}, + {-1, 0, 2000000000, -3, 0}, + {-1, 0, -1, -1, 1}, + {-1, 0, -999999999, -1, 999999999}, + {-1, 0, -1000000000, 0, 0}, + {-1, 0, -1000000001, 0, 1}, + {-1, 0, -1999999999, 0, 999999999}, + + {1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0}, + {1, 1, 999999998, 0, 3}, + {1, 1, 999999999, 0, 2}, + {1, 1, 1000000000, 0, 1}, + {1, 1, 1999999998, -1, 3}, + {1, 1, 1999999999, -1, 2}, + {1, 1, 2000000000, -1, 1}, + {1, 1, -1, 1, 2}, + {1, 1, -2, 1, 3}, + {1, 1, -1000000000, 2, 1}, + {1, 1, -1000000001, 2, 2}, + {1, 1, -1000000002, 2, 3}, + {1, 1, -2000000000, 3, 1}, + + {1, 999999999, 0, 1, 999999999}, + {1, 999999999, 1, 1, 999999998}, + {1, 999999999, 999999999, 1, 0}, + {1, 999999999, 1000000000, 0, 999999999}, + {1, 999999999, 1000000001, 0, 999999998}, + {1, 999999999, -1, 2, 0}, + {1, 999999999, -1000000000, 2, 999999999}, + {1, 999999999, -1000000001, 3, 0}, + {1, 999999999, -1999999999, 3, 999999998}, + {1, 999999999, -2000000000, 3, 999999999}, + + {MAX_SECOND, 0, -999999999, MAX_SECOND, 999999999}, + {MAX_SECOND - 1, 0, -1999999999, MAX_SECOND, 999999999}, + {MIN_SECOND, 1, 1, MIN_SECOND, 0}, + {MIN_SECOND + 1, 1, 1000000001, MIN_SECOND, 0}, + + {0, 0, Long.MAX_VALUE, -(Long.MAX_VALUE / 1000000000) - 1, (int) -(Long.MAX_VALUE % 1000000000) + 1000000000}, + {0, 0, Long.MIN_VALUE, -(Long.MIN_VALUE / 1000000000), (int) -(Long.MIN_VALUE % 1000000000)}, + }; + } + + @Test(dataProvider="MinusNanos") + public void minusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) { + Instant i = Instant.ofEpochSecond(seconds, nanos); + i = i.minusNanos(amount); + assertEquals(i.getEpochSecond(), expectedSeconds); + assertEquals(i.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minusNanos_long_overflowTooBig() { + Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999); + i.minusNanos(-1); + } + + @Test(expectedExceptions=DateTimeException.class) + public void minusNanos_long_overflowTooSmall() { + Instant i = Instant.ofEpochSecond(MIN_SECOND, 0); + i.minusNanos(1); + } + + //----------------------------------------------------------------------- + // toEpochMilli() + //----------------------------------------------------------------------- + @Test + public void test_toEpochMilli() { + assertEquals(Instant.ofEpochSecond(1L, 1000000).toEpochMilli(), 1001L); + assertEquals(Instant.ofEpochSecond(1L, 2000000).toEpochMilli(), 1002L); + assertEquals(Instant.ofEpochSecond(1L, 567).toEpochMilli(), 1000L); + assertEquals(Instant.ofEpochSecond(Long.MAX_VALUE / 1000).toEpochMilli(), (Long.MAX_VALUE / 1000) * 1000); + assertEquals(Instant.ofEpochSecond(Long.MIN_VALUE / 1000).toEpochMilli(), (Long.MIN_VALUE / 1000) * 1000); + assertEquals(Instant.ofEpochSecond(0L, -1000000).toEpochMilli(), -1L); + assertEquals(Instant.ofEpochSecond(0L, 1000000).toEpochMilli(), 1); + assertEquals(Instant.ofEpochSecond(0L, 999999).toEpochMilli(), 0); + assertEquals(Instant.ofEpochSecond(0L, 1).toEpochMilli(), 0); + assertEquals(Instant.ofEpochSecond(0L, 0).toEpochMilli(), 0); + assertEquals(Instant.ofEpochSecond(0L, -1).toEpochMilli(), -1L); + assertEquals(Instant.ofEpochSecond(0L, -999999).toEpochMilli(), -1L); + assertEquals(Instant.ofEpochSecond(0L, -1000000).toEpochMilli(), -1L); + assertEquals(Instant.ofEpochSecond(0L, -1000001).toEpochMilli(), -2L); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_toEpochMilli_tooBig() { + Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1).toEpochMilli(); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_toEpochMilli_tooSmall() { + Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli(); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test + public void test_comparisons() { + doTest_comparisons_Instant( + Instant.ofEpochSecond(-2L, 0), + Instant.ofEpochSecond(-2L, 999999998), + Instant.ofEpochSecond(-2L, 999999999), + Instant.ofEpochSecond(-1L, 0), + Instant.ofEpochSecond(-1L, 1), + Instant.ofEpochSecond(-1L, 999999998), + Instant.ofEpochSecond(-1L, 999999999), + Instant.ofEpochSecond(0L, 0), + Instant.ofEpochSecond(0L, 1), + Instant.ofEpochSecond(0L, 2), + Instant.ofEpochSecond(0L, 999999999), + Instant.ofEpochSecond(1L, 0), + Instant.ofEpochSecond(2L, 0) + ); + } + + void doTest_comparisons_Instant(Instant... instants) { + for (int i = 0; i < instants.length; i++) { + Instant a = instants[i]; + for (int j = 0; j < instants.length; j++) { + Instant b = instants[j]; + if (i < j) { + assertEquals(a.compareTo(b) < 0, true, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(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.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_compareTo_ObjectNull() { + Instant a = Instant.ofEpochSecond(0L, 0); + a.compareTo(null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_isBefore_ObjectNull() { + Instant a = Instant.ofEpochSecond(0L, 0); + a.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_isAfter_ObjectNull() { + Instant a = Instant.ofEpochSecond(0L, 0); + a.isAfter(null); + } + + @Test(expectedExceptions=ClassCastException.class) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonInstant() { + Comparable c = Instant.ofEpochSecond(0L); + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test + public void test_equals() { + Instant test5a = Instant.ofEpochSecond(5L, 20); + Instant test5b = Instant.ofEpochSecond(5L, 20); + Instant test5n = Instant.ofEpochSecond(5L, 30); + Instant test6 = Instant.ofEpochSecond(6L, 20); + + assertEquals(test5a.equals(test5a), true); + assertEquals(test5a.equals(test5b), true); + assertEquals(test5a.equals(test5n), false); + assertEquals(test5a.equals(test6), false); + + assertEquals(test5b.equals(test5a), true); + assertEquals(test5b.equals(test5b), true); + assertEquals(test5b.equals(test5n), false); + assertEquals(test5b.equals(test6), false); + + assertEquals(test5n.equals(test5a), false); + assertEquals(test5n.equals(test5b), false); + assertEquals(test5n.equals(test5n), true); + assertEquals(test5n.equals(test6), false); + + assertEquals(test6.equals(test5a), false); + assertEquals(test6.equals(test5b), false); + assertEquals(test6.equals(test5n), false); + assertEquals(test6.equals(test6), true); + } + + @Test + public void test_equals_null() { + Instant test5 = Instant.ofEpochSecond(5L, 20); + assertEquals(test5.equals(null), false); + } + + @Test + public void test_equals_otherClass() { + Instant test5 = Instant.ofEpochSecond(5L, 20); + assertEquals(test5.equals(""), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test + public void test_hashCode() { + Instant test5a = Instant.ofEpochSecond(5L, 20); + Instant test5b = Instant.ofEpochSecond(5L, 20); + Instant test5n = Instant.ofEpochSecond(5L, 30); + Instant test6 = Instant.ofEpochSecond(6L, 20); + + assertEquals(test5a.hashCode() == test5a.hashCode(), true); + assertEquals(test5a.hashCode() == test5b.hashCode(), true); + assertEquals(test5b.hashCode() == test5b.hashCode(), true); + + assertEquals(test5a.hashCode() == test5n.hashCode(), false); + assertEquals(test5a.hashCode() == test6.hashCode(), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="toStringParse") + Object[][] data_toString() { + return new Object[][] { + {Instant.ofEpochSecond(65L, 567), "1970-01-01T00:01:05.000000567Z"}, + {Instant.ofEpochSecond(1, 0), "1970-01-01T00:00:01Z"}, + {Instant.ofEpochSecond(60, 0), "1970-01-01T00:01Z"}, + {Instant.ofEpochSecond(3600, 0), "1970-01-01T01:00Z"}, + {Instant.ofEpochSecond(-1, 0), "1969-12-31T23:59:59Z"}, + + {LocalDateTime.of(0, 1, 2, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-02T00:00Z"}, + {LocalDateTime.of(0, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "0000-01-01T12:30Z"}, + {LocalDateTime.of(0, 1, 1, 0, 0, 0, 1).toInstant(ZoneOffset.UTC), "0000-01-01T00:00:00.000000001Z"}, + {LocalDateTime.of(0, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-01T00:00Z"}, + + {LocalDateTime.of(-1, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-0001-12-31T23:59:59.999999999Z"}, + {LocalDateTime.of(-1, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-31T12:30Z"}, + {LocalDateTime.of(-1, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-30T12:30Z"}, + + {LocalDateTime.of(-9999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-02T12:30Z"}, + {LocalDateTime.of(-9999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-01T12:30Z"}, + {LocalDateTime.of(-9999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-9999-01-01T00:00Z"}, + + {LocalDateTime.of(-10000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-10000-12-31T23:59:59.999999999Z"}, + {LocalDateTime.of(-10000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-31T12:30Z"}, + {LocalDateTime.of(-10000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-30T12:30Z"}, + {LocalDateTime.of(-15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-15000-12-31T12:30Z"}, + + {LocalDateTime.of(-19999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-02T12:30Z"}, + {LocalDateTime.of(-19999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-01T12:30Z"}, + {LocalDateTime.of(-19999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-19999-01-01T00:00Z"}, + + {LocalDateTime.of(-20000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-20000-12-31T23:59:59.999999999Z"}, + {LocalDateTime.of(-20000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-31T12:30Z"}, + {LocalDateTime.of(-20000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-30T12:30Z"}, + {LocalDateTime.of(-25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-25000-12-31T12:30Z"}, + + {LocalDateTime.of(9999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-30T12:30Z"}, + {LocalDateTime.of(9999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-31T12:30Z"}, + {LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "9999-12-31T23:59:59.999999999Z"}, + + {LocalDateTime.of(10000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+10000-01-01T00:00Z"}, + {LocalDateTime.of(10000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-01T12:30Z"}, + {LocalDateTime.of(10000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-02T12:30Z"}, + {LocalDateTime.of(15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+15000-12-31T12:30Z"}, + + {LocalDateTime.of(19999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-30T12:30Z"}, + {LocalDateTime.of(19999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-31T12:30Z"}, + {LocalDateTime.of(19999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "+19999-12-31T23:59:59.999999999Z"}, + + {LocalDateTime.of(20000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+20000-01-01T00:00Z"}, + {LocalDateTime.of(20000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-01T12:30Z"}, + {LocalDateTime.of(20000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-02T12:30Z"}, + {LocalDateTime.of(25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+25000-12-31T12:30Z"}, + + {LocalDateTime.of(-999_999_999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC).minus(1, DAYS), "-1000000000-12-31T12:30Z"}, + {LocalDateTime.of(999_999_999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC).plus(1, DAYS), "+1000000000-01-01T12:30Z"}, + + {Instant.MIN, "-1000000000-01-01T00:00Z"}, + {Instant.MAX, "+1000000000-12-31T23:59:59.999999999Z"}, + }; + } + + @Test(dataProvider="toStringParse") + public void test_toString(Instant instant, String expected) { + assertEquals(instant.toString(), expected); + } + + @Test(dataProvider="toStringParse") + public void test_parse(Instant instant, String text) { + assertEquals(Instant.parse(text), instant); + } + + @Test(dataProvider="toStringParse") + public void test_parseLowercase(Instant instant, String text) { + assertEquals(Instant.parse(text.toLowerCase(Locale.ENGLISH)), instant); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java new file mode 100644 index 00000000000..721da56d36b --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java @@ -0,0 +1,2018 @@ +/* + * 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) 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; + +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.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.assertNotNull; +import static org.testng.Assert.assertSame; +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; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +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.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.TemporalUnit; +import java.time.temporal.Year; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import test.java.time.MockSimplePeriod; +import test.java.time.temporal.MockFieldNoValue; + +/** + * Test LocalDate. + */ +@Test +public class TCKLocalDate extends AbstractDateTimeTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza"); + + private LocalDate TEST_2007_07_15; + private long MAX_VALID_EPOCHDAYS; + private long MIN_VALID_EPOCHDAYS; + private LocalDate MAX_DATE; + private LocalDate MIN_DATE; + private Instant MAX_INSTANT; + private Instant MIN_INSTANT; + + @BeforeMethod(groups={"tck", "implementation"}) + public void setUp() { + TEST_2007_07_15 = LocalDate.of(2007, 7, 15); + + LocalDate max = LocalDate.MAX; + LocalDate min = LocalDate.MIN; + MAX_VALID_EPOCHDAYS = max.toEpochDay(); + MIN_VALID_EPOCHDAYS = min.toEpochDay(); + MAX_DATE = max; + MIN_DATE = min; + MAX_INSTANT = max.atStartOfDay(ZoneOffset.UTC).toInstant(); + MIN_INSTANT = min.atStartOfDay(ZoneOffset.UTC).toInstant(); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2007_07_15, LocalDate.MAX, LocalDate.MIN, }; + 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, + 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 Exception { + assertSerializable(TEST_2007_07_15); + assertSerializable(LocalDate.MIN); + assertSerializable(LocalDate.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(3); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalDate.of(2012, 9, 16), bytes); + } + + //----------------------------------------------------------------------- + private void check(LocalDate test, int y, int m, int d) { + assertEquals(test.getYear(), y); + assertEquals(test.getMonth().getValue(), m); + assertEquals(test.getDayOfMonth(), d); + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + assertEquals(LocalDate.of(y, m, d), test); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void constant_MIN() { + check(LocalDate.MIN, Year.MIN_VALUE, 1, 1); + } + + @Test + public void constant_MAX() { + check(LocalDate.MAX, Year.MAX_VALUE, 12, 31); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + LocalDate expected = LocalDate.now(Clock.systemDefaultZone()); + LocalDate test = LocalDate.now(); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = LocalDate.now(Clock.systemDefaultZone()); + test = LocalDate.now(); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + LocalDate.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + LocalDate expected = LocalDate.now(Clock.system(zone)); + LocalDate test = LocalDate.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = LocalDate.now(Clock.system(zone)); + test = LocalDate.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + LocalDate.now((Clock) null); + } + + @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); + LocalDate test = LocalDate.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2)); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_offset() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE); + LocalDate test = LocalDate.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2); + } + } + + @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); + LocalDate test = LocalDate.now(clock); + assertEquals(test.getYear(), 1969); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), (i >= -24 * 60 * 60 ? 31 : 30)); + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock_maxYear() { + Clock clock = Clock.fixed(MAX_INSTANT, ZoneOffset.UTC); + LocalDate test = LocalDate.now(clock); + assertEquals(test, MAX_DATE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void now_Clock_tooBig() { + Clock clock = Clock.fixed(MAX_INSTANT.plusSeconds(24 * 60 * 60), ZoneOffset.UTC); + LocalDate.now(clock); + } + + @Test(groups={"tck"}) + public void now_Clock_minYear() { + Clock clock = Clock.fixed(MIN_INSTANT, ZoneOffset.UTC); + LocalDate test = LocalDate.now(clock); + assertEquals(test, MIN_DATE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void now_Clock_tooLow() { + Clock clock = Clock.fixed(MIN_INSTANT.minusNanos(1), ZoneOffset.UTC); + LocalDate.now(clock); + } + + //----------------------------------------------------------------------- + // of() factories + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_intsMonth() { + assertEquals(TEST_2007_07_15, LocalDate.of(2007, Month.JULY, 15)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_intsMonth_29febNonLeap() { + LocalDate.of(2007, Month.FEBRUARY, 29); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_intsMonth_31apr() { + LocalDate.of(2007, Month.APRIL, 31); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_intsMonth_dayTooLow() { + LocalDate.of(2007, Month.JANUARY, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_intsMonth_dayTooHigh() { + LocalDate.of(2007, Month.JANUARY, 32); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_intsMonth_nullMonth() { + LocalDate.of(2007, null, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_intsMonth_yearTooLow() { + LocalDate.of(Integer.MIN_VALUE, Month.JANUARY, 1); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_ints() { + check(TEST_2007_07_15, 2007, 7, 15); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_29febNonLeap() { + LocalDate.of(2007, 2, 29); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_31apr() { + LocalDate.of(2007, 4, 31); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_dayTooLow() { + LocalDate.of(2007, 1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_dayTooHigh() { + LocalDate.of(2007, 1, 32); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_monthTooLow() { + LocalDate.of(2007, 0, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_monthTooHigh() { + LocalDate.of(2007, 13, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_ints_yearTooLow() { + LocalDate.of(Integer.MIN_VALUE, 1, 1); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofYearDay_ints_nonLeap() { + LocalDate date = LocalDate.of(2007, 1, 1); + for (int i = 1; i < 365; i++) { + assertEquals(LocalDate.ofYearDay(2007, i), date); + date = next(date); + } + } + + @Test(groups={"tck"}) + public void factory_ofYearDay_ints_leap() { + LocalDate date = LocalDate.of(2008, 1, 1); + for (int i = 1; i < 366; i++) { + assertEquals(LocalDate.ofYearDay(2008, i), date); + date = next(date); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofYearDay_ints_366nonLeap() { + LocalDate.ofYearDay(2007, 366); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofYearDay_ints_dayTooLow() { + LocalDate.ofYearDay(2007, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofYearDay_ints_dayTooHigh() { + LocalDate.ofYearDay(2007, 367); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofYearDay_ints_yearTooLow() { + LocalDate.ofYearDay(Integer.MIN_VALUE, 1); + } + + //----------------------------------------------------------------------- + // Since plusDays/minusDays actually depends on MJDays, it cannot be used for testing + private LocalDate next(LocalDate date) { + int newDayOfMonth = date.getDayOfMonth() + 1; + if (newDayOfMonth <= date.getMonth().length(isIsoLeap(date.getYear()))) { + return date.withDayOfMonth(newDayOfMonth); + } + date = date.withDayOfMonth(1); + if (date.getMonth() == Month.DECEMBER) { + date = date.withYear(date.getYear() + 1); + } + return date.with(date.getMonth().plus(1)); + } + + private LocalDate previous(LocalDate date) { + int newDayOfMonth = date.getDayOfMonth() - 1; + if (newDayOfMonth > 0) { + return date.withDayOfMonth(newDayOfMonth); + } + date = date.with(date.getMonth().minus(1)); + if (date.getMonth() == Month.DECEMBER) { + date = date.withYear(date.getYear() - 1); + } + return date.withDayOfMonth(date.getMonth().length(isIsoLeap(date.getYear()))); + } + + //----------------------------------------------------------------------- + // ofEpochDay() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofEpochDay() { + long date_0000_01_01 = -678941 - 40587; + assertEquals(LocalDate.ofEpochDay(0), LocalDate.of(1970, 1, 1)); + assertEquals(LocalDate.ofEpochDay(date_0000_01_01), LocalDate.of(0, 1, 1)); + assertEquals(LocalDate.ofEpochDay(date_0000_01_01 - 1), LocalDate.of(-1, 12, 31)); + assertEquals(LocalDate.ofEpochDay(MAX_VALID_EPOCHDAYS), LocalDate.of(Year.MAX_VALUE, 12, 31)); + assertEquals(LocalDate.ofEpochDay(MIN_VALID_EPOCHDAYS), LocalDate.of(Year.MIN_VALUE, 1, 1)); + + LocalDate test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i < 700000; i++) { + assertEquals(LocalDate.ofEpochDay(i), test); + test = next(test); + } + test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i > -2000000; i--) { + assertEquals(LocalDate.ofEpochDay(i), test); + test = previous(test); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochDay_aboveMax() { + LocalDate.ofEpochDay(MAX_VALID_EPOCHDAYS + 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochDay_belowMin() { + LocalDate.ofEpochDay(MIN_VALID_EPOCHDAYS - 1); + } + + //----------------------------------------------------------------------- + // from() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_from_TemporalAccessor() { + assertEquals(LocalDate.from(LocalDate.of(2007, 7, 15)), LocalDate.of(2007, 7, 15)); + assertEquals(LocalDate.from(LocalDateTime.of(2007, 7, 15, 12, 30)), LocalDate.of(2007, 7, 15)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_from_TemporalAccessor_invalid_noDerive() { + LocalDate.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_from_TemporalAccessor_null() { + LocalDate.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleToString", groups={"tck"}) + public void factory_parse_validText(int y, int m, int d, String parsable) { + LocalDate t = LocalDate.parse(parsable); + assertNotNull(t, parsable); + assertEquals(t.getYear(), y, parsable); + assertEquals(t.getMonth().getValue(), m, parsable); + assertEquals(t.getDayOfMonth(), d, parsable); + } + + @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-01Z"}, + {"2008-02-01+01:00"}, + {"2008-02-01+01:00[Europe/Paris]"}, + }; + } + + @Test(dataProvider="sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_invalidText(String unparsable) { + LocalDate.parse(unparsable); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue() { + LocalDate.parse("2008-06-32"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_invalidValue() { + LocalDate.parse("2008-06-31"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + LocalDate.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + LocalDate.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + LocalDate.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + LocalDate test = LocalDate.of(2008, 6, 30); + 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); + } + + @Test + public void test_getLong_TemporalField() { + LocalDate test = LocalDate.of(2008, 6, 30); + 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); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_2007_07_15.query(null); + } + + //----------------------------------------------------------------------- + // get*() + //----------------------------------------------------------------------- + @DataProvider(name="sampleDates") + Object[][] provider_sampleDates() { + return new Object[][] { + {2008, 7, 5}, + {2007, 7, 5}, + {2006, 7, 5}, + {2005, 7, 5}, + {2004, 1, 1}, + {-1, 1, 2}, + }; + } + + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_get(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + assertEquals(a.getYear(), y); + assertEquals(a.getMonth(), Month.of(m)); + assertEquals(a.getDayOfMonth(), d); + } + + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_getDOY(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + int total = 0; + for (int i = 1; i < m; i++) { + total += Month.of(i).length(isIsoLeap(y)); + } + int doy = total + d; + assertEquals(a.getDayOfYear(), doy); + } + + @Test(groups={"tck"}) + public void test_getDayOfWeek() { + DayOfWeek dow = DayOfWeek.MONDAY; + for (Month month : Month.values()) { + int length = month.length(false); + for (int i = 1; i <= length; i++) { + LocalDate d = LocalDate.of(2007, month, i); + assertSame(d.getDayOfWeek(), dow); + dow = dow.plus(1); + } + } + } + + //----------------------------------------------------------------------- + // isLeapYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isLeapYear() { + assertEquals(LocalDate.of(1999, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(2000, 1, 1).isLeapYear(), true); + assertEquals(LocalDate.of(2001, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(2002, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(2003, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(2004, 1, 1).isLeapYear(), true); + assertEquals(LocalDate.of(2005, 1, 1).isLeapYear(), false); + + assertEquals(LocalDate.of(1500, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(1600, 1, 1).isLeapYear(), true); + assertEquals(LocalDate.of(1700, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(1800, 1, 1).isLeapYear(), false); + assertEquals(LocalDate.of(1900, 1, 1).isLeapYear(), false); + } + + //----------------------------------------------------------------------- + // lengthOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_lengthOfMonth_notLeapYear() { + assertEquals(LocalDate.of(2007, 1, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 2, 1).lengthOfMonth(), 28); + assertEquals(LocalDate.of(2007, 3, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 4, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2007, 5, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 6, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2007, 7, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 8, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 9, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2007, 10, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2007, 11, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2007, 12, 1).lengthOfMonth(), 31); + } + + @Test(groups={"tck"}) + public void test_lengthOfMonth_leapYear() { + assertEquals(LocalDate.of(2008, 1, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 2, 1).lengthOfMonth(), 29); + assertEquals(LocalDate.of(2008, 3, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 4, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2008, 5, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 6, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2008, 7, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 8, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 9, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2008, 10, 1).lengthOfMonth(), 31); + assertEquals(LocalDate.of(2008, 11, 1).lengthOfMonth(), 30); + assertEquals(LocalDate.of(2008, 12, 1).lengthOfMonth(), 31); + } + + //----------------------------------------------------------------------- + // lengthOfYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_lengthOfYear() { + assertEquals(LocalDate.of(2007, 1, 1).lengthOfYear(), 365); + assertEquals(LocalDate.of(2008, 1, 1).lengthOfYear(), 366); + } + + //----------------------------------------------------------------------- + // with() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_adjustment() { + final LocalDate sample = LocalDate.of(2012, 3, 4); + TemporalAdjuster adjuster = new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return sample; + } + }; + assertEquals(TEST_2007_07_15.with(adjuster), sample); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_adjustment_null() { + TEST_2007_07_15.with((TemporalAdjuster) null); + } + + //----------------------------------------------------------------------- + // with(TemporalField,long) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_TemporalField_long_normal() { + LocalDate t = TEST_2007_07_15.with(YEAR, 2008); + assertEquals(t, LocalDate.of(2008, 7, 15)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"} ) + public void test_with_TemporalField_long_null() { + TEST_2007_07_15.with((TemporalField) null, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"} ) + public void test_with_TemporalField_long_invalidField() { + TEST_2007_07_15.with(MockFieldNoValue.INSTANCE, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"} ) + public void test_with_TemporalField_long_timeField() { + TEST_2007_07_15.with(ChronoField.AMPM_OF_DAY, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"} ) + public void test_with_TemporalField_long_invalidValue() { + TEST_2007_07_15.with(ChronoField.DAY_OF_WEEK, -1); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear_int_normal() { + LocalDate t = TEST_2007_07_15.withYear(2008); + assertEquals(t, LocalDate.of(2008, 7, 15)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withYear_int_invalid() { + TEST_2007_07_15.withYear(Year.MIN_VALUE - 1); + } + + @Test(groups={"tck"}) + public void test_withYear_int_adjustDay() { + LocalDate t = LocalDate.of(2008, 2, 29).withYear(2007); + LocalDate expected = LocalDate.of(2007, 2, 28); + assertEquals(t, expected); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth_int_normal() { + LocalDate t = TEST_2007_07_15.withMonth(1); + assertEquals(t, LocalDate.of(2007, 1, 15)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_int_invalid() { + TEST_2007_07_15.withMonth(13); + } + + @Test(groups={"tck"}) + public void test_withMonth_int_adjustDay() { + LocalDate t = LocalDate.of(2007, 12, 31).withMonth(11); + LocalDate expected = LocalDate.of(2007, 11, 30); + assertEquals(t, expected); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfMonth_normal() { + LocalDate t = TEST_2007_07_15.withDayOfMonth(1); + assertEquals(t, LocalDate.of(2007, 7, 1)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_illegal() { + TEST_2007_07_15.withDayOfMonth(32); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_invalid() { + LocalDate.of(2007, 11, 30).withDayOfMonth(31); + } + + //----------------------------------------------------------------------- + // withDayOfYear(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfYear_normal() { + LocalDate t = TEST_2007_07_15.withDayOfYear(33); + assertEquals(t, LocalDate.of(2007, 2, 2)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_illegal() { + TEST_2007_07_15.withDayOfYear(367); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_invalid() { + TEST_2007_07_15.withDayOfYear(366); + } + + //----------------------------------------------------------------------- + // plus(Period) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plus_Period_positiveMonths() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + LocalDate t = TEST_2007_07_15.plus(period); + assertEquals(t, LocalDate.of(2008, 2, 15)); + } + + @Test(groups={"tck"}) + public void test_plus_Period_negativeDays() { + MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS); + LocalDate t = TEST_2007_07_15.plus(period); + assertEquals(t, LocalDate.of(2007, 6, 20)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_plus_Period_timeNotAllowed() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.HOURS); + TEST_2007_07_15.plus(period); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_Period_null() { + TEST_2007_07_15.plus((MockSimplePeriod) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_Period_invalidTooLarge() { + MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS); + LocalDate.of(Year.MAX_VALUE, 1, 1).plus(period); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_Period_invalidTooSmall() { + MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS); + LocalDate.of(Year.MIN_VALUE, 1, 1).plus(period); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_positiveMonths() { + LocalDate t = TEST_2007_07_15.plus(7, ChronoUnit.MONTHS); + assertEquals(t, LocalDate.of(2008, 2, 15)); + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_negativeDays() { + LocalDate t = TEST_2007_07_15.plus(-25, ChronoUnit.DAYS); + assertEquals(t, LocalDate.of(2007, 6, 20)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_plus_longTemporalUnit_timeNotAllowed() { + TEST_2007_07_15.plus(7, ChronoUnit.HOURS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_null() { + TEST_2007_07_15.plus(1, (TemporalUnit) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 1, 1).plus(1, ChronoUnit.YEARS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plus(-1, ChronoUnit.YEARS); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears_long_normal() { + LocalDate t = TEST_2007_07_15.plusYears(1); + assertEquals(t, LocalDate.of(2008, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_negative() { + LocalDate t = TEST_2007_07_15.plusYears(-1); + assertEquals(t, LocalDate.of(2006, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_adjustDay() { + LocalDate t = LocalDate.of(2008, 2, 29).plusYears(1); + LocalDate expected = LocalDate.of(2009, 2, 28); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_big() { + long years = 20L + Year.MAX_VALUE; + LocalDate test = LocalDate.of(-40, 6, 1).plusYears(years); + assertEquals(test, LocalDate.of((int) (-40L + years), 6, 1)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLarge() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 6, 1); + test.plusYears(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLargeMaxAddMax() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.plusYears(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLargeMaxAddMin() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.plusYears(Long.MIN_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooSmall_validInt() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooSmall_invalidInt() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-10); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMonths_long_normal() { + LocalDate t = TEST_2007_07_15.plusMonths(1); + assertEquals(t, LocalDate.of(2007, 8, 15)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_overYears() { + LocalDate t = TEST_2007_07_15.plusMonths(25); + assertEquals(t, LocalDate.of(2009, 8, 15)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_negative() { + LocalDate t = TEST_2007_07_15.plusMonths(-1); + assertEquals(t, LocalDate.of(2007, 6, 15)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.plusMonths(-7); + assertEquals(t, LocalDate.of(2006, 12, 15)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_negativeOverYears() { + LocalDate t = TEST_2007_07_15.plusMonths(-31); + assertEquals(t, LocalDate.of(2004, 12, 15)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_adjustDayFromLeapYear() { + LocalDate t = LocalDate.of(2008, 2, 29).plusMonths(12); + LocalDate expected = LocalDate.of(2009, 2, 28); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_adjustDayFromMonthLength() { + LocalDate t = LocalDate.of(2007, 3, 31).plusMonths(1); + LocalDate expected = LocalDate.of(2007, 4, 30); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_big() { + long months = 20L + Integer.MAX_VALUE; + LocalDate test = LocalDate.of(-40, 6, 1).plusMonths(months); + assertEquals(test, LocalDate.of((int) (-40L + months / 12), 6 + (int) (months % 12), 1)); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusMonths_long_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 1).plusMonths(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_long_invalidTooLargeMaxAddMax() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.plusMonths(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_long_invalidTooLargeMaxAddMin() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.plusMonths(Long.MIN_VALUE); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusMonths_long_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusMonths(-1); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_normal() { + LocalDate t = TEST_2007_07_15.plusWeeks(1); + assertEquals(t, LocalDate.of(2007, 7, 22)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overMonths() { + LocalDate t = TEST_2007_07_15.plusWeeks(9); + assertEquals(t, LocalDate.of(2007, 9, 16)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overYears() { + LocalDate t = LocalDate.of(2006, 7, 16).plusWeeks(52); + assertEquals(t, TEST_2007_07_15); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overLeapYears() { + LocalDate t = TEST_2007_07_15.plusYears(-1).plusWeeks(104); + assertEquals(t, LocalDate.of(2008, 7, 12)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negative() { + LocalDate t = TEST_2007_07_15.plusWeeks(-1); + assertEquals(t, LocalDate.of(2007, 7, 8)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.plusWeeks(-28); + assertEquals(t, LocalDate.of(2006, 12, 31)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negativeOverYears() { + LocalDate t = TEST_2007_07_15.plusWeeks(-104); + assertEquals(t, LocalDate.of(2005, 7, 17)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_maximum() { + LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 24).plusWeeks(1); + LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_minimum() { + LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 8).plusWeeks(-1); + LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1); + assertEquals(t, expected); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusWeeks_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(1); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusWeeks_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 7).plusWeeks(-1); + } + + @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) + public void test_plusWeeks_invalidMaxMinusMax() { + LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(Long.MAX_VALUE); + } + + @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) + public void test_plusWeeks_invalidMaxMinusMin() { + LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(Long.MIN_VALUE); + } + + @Test(groups={"tck"}) + public void test_plusDays_normal() { + LocalDate t = TEST_2007_07_15.plusDays(1); + assertEquals(t, LocalDate.of(2007, 7, 16)); + } + + @Test(groups={"tck"}) + public void test_plusDays_overMonths() { + LocalDate t = TEST_2007_07_15.plusDays(62); + assertEquals(t, LocalDate.of(2007, 9, 15)); + } + + @Test(groups={"tck"}) + public void test_plusDays_overYears() { + LocalDate t = LocalDate.of(2006, 7, 14).plusDays(366); + assertEquals(t, TEST_2007_07_15); + } + + @Test(groups={"tck"}) + public void test_plusDays_overLeapYears() { + LocalDate t = TEST_2007_07_15.plusYears(-1).plusDays(365 + 366); + assertEquals(t, LocalDate.of(2008, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_plusDays_negative() { + LocalDate t = TEST_2007_07_15.plusDays(-1); + assertEquals(t, LocalDate.of(2007, 7, 14)); + } + + @Test(groups={"tck"}) + public void test_plusDays_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.plusDays(-196); + assertEquals(t, LocalDate.of(2006, 12, 31)); + } + + @Test(groups={"tck"}) + public void test_plusDays_negativeOverYears() { + LocalDate t = TEST_2007_07_15.plusDays(-730); + assertEquals(t, LocalDate.of(2005, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_plusDays_maximum() { + LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 30).plusDays(1); + LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_plusDays_minimum() { + LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 2).plusDays(-1); + LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1); + assertEquals(t, expected); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusDays_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 31).plusDays(1); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusDays_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusDays(-1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_plusDays_overflowTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 31).plusDays(Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_plusDays_overflowTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusDays(Long.MIN_VALUE); + } + + //----------------------------------------------------------------------- + // minus(Period) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minus_Period_positiveMonths() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + LocalDate t = TEST_2007_07_15.minus(period); + assertEquals(t, LocalDate.of(2006, 12, 15)); + } + + @Test(groups={"tck"}) + public void test_minus_Period_negativeDays() { + MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS); + LocalDate t = TEST_2007_07_15.minus(period); + assertEquals(t, LocalDate.of(2007, 8, 9)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_minus_Period_timeNotAllowed() { + MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.HOURS); + TEST_2007_07_15.minus(period); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_Period_null() { + TEST_2007_07_15.minus((MockSimplePeriod) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_Period_invalidTooLarge() { + MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS); + LocalDate.of(Year.MAX_VALUE, 1, 1).minus(period); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_Period_invalidTooSmall() { + MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS); + LocalDate.of(Year.MIN_VALUE, 1, 1).minus(period); + } + + //----------------------------------------------------------------------- + // minus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_positiveMonths() { + LocalDate t = TEST_2007_07_15.minus(7, ChronoUnit.MONTHS); + assertEquals(t, LocalDate.of(2006, 12, 15)); + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_negativeDays() { + LocalDate t = TEST_2007_07_15.minus(-25, ChronoUnit.DAYS); + assertEquals(t, LocalDate.of(2007, 8, 9)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_minus_longTemporalUnit_timeNotAllowed() { + TEST_2007_07_15.minus(7, ChronoUnit.HOURS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_null() { + TEST_2007_07_15.minus(1, (TemporalUnit) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 1, 1).minus(-1, ChronoUnit.YEARS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).minus(1, ChronoUnit.YEARS); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears_long_normal() { + LocalDate t = TEST_2007_07_15.minusYears(1); + assertEquals(t, LocalDate.of(2006, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_negative() { + LocalDate t = TEST_2007_07_15.minusYears(-1); + assertEquals(t, LocalDate.of(2008, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_adjustDay() { + LocalDate t = LocalDate.of(2008, 2, 29).minusYears(1); + LocalDate expected = LocalDate.of(2007, 2, 28); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_big() { + long years = 20L + Year.MAX_VALUE; + LocalDate test = LocalDate.of(40, 6, 1).minusYears(years); + assertEquals(test, LocalDate.of((int) (40L - years), 6, 1)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLarge() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 6, 1); + test.minusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLargeMaxAddMax() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.minusYears(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLargeMaxAddMin() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.minusYears(Long.MIN_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).minusYears(1); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMonths_long_normal() { + LocalDate t = TEST_2007_07_15.minusMonths(1); + assertEquals(t, LocalDate.of(2007, 6, 15)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_overYears() { + LocalDate t = TEST_2007_07_15.minusMonths(25); + assertEquals(t, LocalDate.of(2005, 6, 15)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_negative() { + LocalDate t = TEST_2007_07_15.minusMonths(-1); + assertEquals(t, LocalDate.of(2007, 8, 15)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.minusMonths(-7); + assertEquals(t, LocalDate.of(2008, 2, 15)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_negativeOverYears() { + LocalDate t = TEST_2007_07_15.minusMonths(-31); + assertEquals(t, LocalDate.of(2010, 2, 15)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_adjustDayFromLeapYear() { + LocalDate t = LocalDate.of(2008, 2, 29).minusMonths(12); + LocalDate expected = LocalDate.of(2007, 2, 28); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_adjustDayFromMonthLength() { + LocalDate t = LocalDate.of(2007, 3, 31).minusMonths(1); + LocalDate expected = LocalDate.of(2007, 2, 28); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_big() { + long months = 20L + Integer.MAX_VALUE; + LocalDate test = LocalDate.of(40, 6, 1).minusMonths(months); + assertEquals(test, LocalDate.of((int) (40L - months / 12), 6 - (int) (months % 12), 1)); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusMonths_long_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 1).minusMonths(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_long_invalidTooLargeMaxAddMax() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.minusMonths(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_long_invalidTooLargeMaxAddMin() { + LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1); + test.minusMonths(Long.MIN_VALUE); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusMonths_long_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).minusMonths(1); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_normal() { + LocalDate t = TEST_2007_07_15.minusWeeks(1); + assertEquals(t, LocalDate.of(2007, 7, 8)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overMonths() { + LocalDate t = TEST_2007_07_15.minusWeeks(9); + assertEquals(t, LocalDate.of(2007, 5, 13)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overYears() { + LocalDate t = LocalDate.of(2008, 7, 13).minusWeeks(52); + assertEquals(t, TEST_2007_07_15); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overLeapYears() { + LocalDate t = TEST_2007_07_15.minusYears(-1).minusWeeks(104); + assertEquals(t, LocalDate.of(2006, 7, 18)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negative() { + LocalDate t = TEST_2007_07_15.minusWeeks(-1); + assertEquals(t, LocalDate.of(2007, 7, 22)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.minusWeeks(-28); + assertEquals(t, LocalDate.of(2008, 1, 27)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negativeOverYears() { + LocalDate t = TEST_2007_07_15.minusWeeks(-104); + assertEquals(t, LocalDate.of(2009, 7, 12)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_maximum() { + LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 24).minusWeeks(-1); + LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_minimum() { + LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 8).minusWeeks(1); + LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1); + assertEquals(t, expected); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusWeeks_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(-1); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusWeeks_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 7).minusWeeks(1); + } + + @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) + public void test_minusWeeks_invalidMaxMinusMax() { + LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(Long.MAX_VALUE); + } + + @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) + public void test_minusWeeks_invalidMaxMinusMin() { + LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(Long.MIN_VALUE); + } + + @Test(groups={"tck"}) + public void test_minusDays_normal() { + LocalDate t = TEST_2007_07_15.minusDays(1); + assertEquals(t, LocalDate.of(2007, 7, 14)); + } + + @Test(groups={"tck"}) + public void test_minusDays_overMonths() { + LocalDate t = TEST_2007_07_15.minusDays(62); + assertEquals(t, LocalDate.of(2007, 5, 14)); + } + + @Test(groups={"tck"}) + public void test_minusDays_overYears() { + LocalDate t = LocalDate.of(2008, 7, 16).minusDays(367); + assertEquals(t, TEST_2007_07_15); + } + + @Test(groups={"tck"}) + public void test_minusDays_overLeapYears() { + LocalDate t = TEST_2007_07_15.plusYears(2).minusDays(365 + 366); + assertEquals(t, TEST_2007_07_15); + } + + @Test(groups={"tck"}) + public void test_minusDays_negative() { + LocalDate t = TEST_2007_07_15.minusDays(-1); + assertEquals(t, LocalDate.of(2007, 7, 16)); + } + + @Test(groups={"tck"}) + public void test_minusDays_negativeAcrossYear() { + LocalDate t = TEST_2007_07_15.minusDays(-169); + assertEquals(t, LocalDate.of(2007, 12, 31)); + } + + @Test(groups={"tck"}) + public void test_minusDays_negativeOverYears() { + LocalDate t = TEST_2007_07_15.minusDays(-731); + assertEquals(t, LocalDate.of(2009, 7, 15)); + } + + @Test(groups={"tck"}) + public void test_minusDays_maximum() { + LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 30).minusDays(-1); + LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31); + assertEquals(t, expected); + } + + @Test(groups={"tck"}) + public void test_minusDays_minimum() { + LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 2).minusDays(1); + LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1); + assertEquals(t, expected); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusDays_invalidTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 31).minusDays(-1); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusDays_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).minusDays(1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_minusDays_overflowTooLarge() { + LocalDate.of(Year.MAX_VALUE, 12, 31).minusDays(Long.MIN_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_minusDays_overflowTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).minusDays(Long.MAX_VALUE); + } + + //----------------------------------------------------------------------- + // atTime() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atTime_LocalTime() { + LocalDate t = LocalDate.of(2008, 6, 30); + assertEquals(t.atTime(LocalTime.of(11, 30)), LocalDateTime.of(2008, 6, 30, 11, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atTime_LocalTime_null() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime((LocalTime) null); + } + + //------------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atTime_int_int() { + LocalDate t = LocalDate.of(2008, 6, 30); + assertEquals(t.atTime(11, 30), LocalDateTime.of(2008, 6, 30, 11, 30)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_hourTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(-1, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_hourTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(24, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_minuteTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_minuteTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 60); + } + + @Test(groups={"tck"}) + public void test_atTime_int_int_int() { + LocalDate t = LocalDate.of(2008, 6, 30); + assertEquals(t.atTime(11, 30, 40), LocalDateTime.of(2008, 6, 30, 11, 30, 40)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_hourTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(-1, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_hourTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(24, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_minuteTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, -1, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_minuteTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 60, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_secondTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_secondTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, 60); + } + + @Test(groups={"tck"}) + public void test_atTime_int_int_int_int() { + LocalDate t = LocalDate.of(2008, 6, 30); + assertEquals(t.atTime(11, 30, 40, 50), LocalDateTime.of(2008, 6, 30, 11, 30, 40, 50)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_hourTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(-1, 30, 40, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_hourTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(24, 30, 40, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_minuteTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, -1, 40, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_minuteTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 60, 40, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_secondTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, -1, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_secondTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, 60, 50); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_nanoTooSmall() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, 40, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atTime_int_int_int_int_nanoTooBig() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atTime(11, 30, 40, 1000000000); + } + + //----------------------------------------------------------------------- + // atOffset() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atOffset() { + LocalDate t = LocalDate.of(2008, 6, 30); + assertEquals(t.atOffset(OFFSET_PTWO), OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atOffset_nullZoneOffset() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atOffset((ZoneOffset) 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)); + } + + @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(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atStartOfDay_nullTimeZone() { + LocalDate t = LocalDate.of(2008, 6, 30); + t.atStartOfDay((ZoneId) null); + } + + //----------------------------------------------------------------------- + // toEpochDay() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toEpochDay() { + long date_0000_01_01 = -678941 - 40587; + + LocalDate test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i < 700000; i++) { + assertEquals(test.toEpochDay(), i); + test = next(test); + } + test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i > -2000000; i--) { + assertEquals(test.toEpochDay(), i); + test = previous(test); + } + + assertEquals(LocalDate.of(1858, 11, 17).toEpochDay(), -40587); + assertEquals(LocalDate.of(1, 1, 1).toEpochDay(), -678575 - 40587); + assertEquals(LocalDate.of(1995, 9, 27).toEpochDay(), 49987 - 40587); + assertEquals(LocalDate.of(1970, 1, 1).toEpochDay(), 0); + assertEquals(LocalDate.of(-1, 12, 31).toEpochDay(), -678942 - 40587); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + doTest_comparisons_LocalDate( + LocalDate.of(Year.MIN_VALUE, 1, 1), + LocalDate.of(Year.MIN_VALUE, 12, 31), + LocalDate.of(-1, 1, 1), + LocalDate.of(-1, 12, 31), + LocalDate.of(0, 1, 1), + LocalDate.of(0, 12, 31), + LocalDate.of(1, 1, 1), + LocalDate.of(1, 12, 31), + LocalDate.of(2006, 1, 1), + LocalDate.of(2006, 12, 31), + LocalDate.of(2007, 1, 1), + LocalDate.of(2007, 12, 31), + LocalDate.of(2008, 1, 1), + LocalDate.of(2008, 2, 29), + LocalDate.of(2008, 12, 31), + LocalDate.of(Year.MAX_VALUE, 1, 1), + LocalDate.of(Year.MAX_VALUE, 12, 31) + ); + } + + void doTest_comparisons_LocalDate(LocalDate... localDates) { + for (int i = 0; i < localDates.length; i++) { + LocalDate a = localDates[i]; + for (int j = 0; j < localDates.length; j++) { + LocalDate b = localDates[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + TEST_2007_07_15.compareTo(null); + } + + @Test(groups={"tck"}) + public void test_isBefore() { + assertTrue(TEST_2007_07_15.isBefore(LocalDate.of(2007, 07, 16))); + assertFalse(TEST_2007_07_15.isBefore(LocalDate.of(2007, 07, 14))); + assertFalse(TEST_2007_07_15.isBefore(TEST_2007_07_15)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isBefore_ObjectNull() { + TEST_2007_07_15.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isAfter_ObjectNull() { + TEST_2007_07_15.isAfter(null); + } + + @Test(groups={"tck"}) + public void test_isAfter() { + assertTrue(TEST_2007_07_15.isAfter(LocalDate.of(2007, 07, 14))); + assertFalse(TEST_2007_07_15.isAfter(LocalDate.of(2007, 07, 16))); + assertFalse(TEST_2007_07_15.isAfter(TEST_2007_07_15)); + } + + @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonLocalDate() { + Comparable c = TEST_2007_07_15; + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates" , groups={"tck"}) + public void test_equals_true(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + LocalDate b = LocalDate.of(y, m, d); + assertEquals(a.equals(b), true); + } + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_equals_false_year_differs(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + LocalDate b = LocalDate.of(y + 1, m, d); + assertEquals(a.equals(b), false); + } + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_equals_false_month_differs(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + LocalDate b = LocalDate.of(y, m + 1, d); + assertEquals(a.equals(b), false); + } + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_equals_false_day_differs(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + LocalDate b = LocalDate.of(y, m, d + 1); + assertEquals(a.equals(b), false); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_2007_07_15.equals(TEST_2007_07_15), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_2007_07_15.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_2007_07_15.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_hashCode(int y, int m, int d) { + LocalDate a = LocalDate.of(y, m, d); + assertEquals(a.hashCode(), a.hashCode()); + LocalDate b = LocalDate.of(y, m, d); + assertEquals(a.hashCode(), b.hashCode()); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {2008, 7, 5, "2008-07-05"}, + {2007, 12, 31, "2007-12-31"}, + {999, 12, 31, "0999-12-31"}, + {-1, 1, 2, "-0001-01-02"}, + {9999, 12, 31, "9999-12-31"}, + {-9999, 12, 31, "-9999-12-31"}, + {10000, 1, 1, "+10000-01-01"}, + {-10000, 1, 1, "-10000-01-01"}, + {12345678, 1, 1, "+12345678-01-01"}, + {-12345678, 1, 1, "-12345678-01-01"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int y, int m, int d, String expected) { + LocalDate t = LocalDate.of(y, m, d); + 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 = LocalDate.of(2010, 12, 3).toString(f); + assertEquals(t, "2010 12 3"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + LocalDate.of(2010, 12, 3).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java new file mode 100644 index 00000000000..1fa08f3c93e --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java @@ -0,0 +1,3045 @@ +/* + * 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 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.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +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.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +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.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertSame; +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; +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.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.TemporalQuery; +import java.time.temporal.TemporalSubtractor; +import java.time.temporal.TemporalUnit; +import java.time.temporal.Year; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import test.java.time.MockSimplePeriod; + +/** + * Test LocalDateTime. + */ +@Test +public class TCKLocalDateTime extends AbstractDateTimeTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2); + private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza"); + + private LocalDateTime TEST_2007_07_15_12_30_40_987654321 = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321); + private LocalDateTime MAX_DATE_TIME; + private LocalDateTime MIN_DATE_TIME; + private Instant MAX_INSTANT; + private Instant MIN_INSTANT; + + @BeforeMethod(groups={"implementation","tck"}) + public void setUp() { + MAX_DATE_TIME = LocalDateTime.MAX; + MIN_DATE_TIME = LocalDateTime.MIN; + MAX_INSTANT = MAX_DATE_TIME.atZone(ZoneOffset.UTC).toInstant(); + MIN_INSTANT = MIN_DATE_TIME.atZone(ZoneOffset.UTC).toInstant(); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2007_07_15_12_30_40_987654321, LocalDateTime.MAX, LocalDateTime.MIN, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + NANO_OF_DAY, + MICRO_OF_SECOND, + MICRO_OF_DAY, + MILLI_OF_SECOND, + MILLI_OF_DAY, + SECOND_OF_MINUTE, + SECOND_OF_DAY, + MINUTE_OF_HOUR, + MINUTE_OF_DAY, + CLOCK_HOUR_OF_AMPM, + HOUR_OF_AMPM, + CLOCK_HOUR_OF_DAY, + HOUR_OF_DAY, + AMPM_OF_DAY, + 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, + 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; + } + + //----------------------------------------------------------------------- + private void check(LocalDateTime test, int y, int m, int d, int h, int mi, int s, int n) { + assertEquals(test.getYear(), y); + assertEquals(test.getMonth().getValue(), m); + assertEquals(test.getDayOfMonth(), d); + assertEquals(test.getHour(), h); + assertEquals(test.getMinute(), mi); + assertEquals(test.getSecond(), s); + assertEquals(test.getNano(), n); + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + assertEquals(LocalDateTime.of(y, m, d, h, mi, s, n), test); + } + + private LocalDateTime createDateMidnight(int year, int month, int day) { + return LocalDateTime.of(year, month, day, 0, 0); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_2007_07_15_12_30_40_987654321); + assertSerializable(LocalDateTime.MIN); + assertSerializable(LocalDateTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(5); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(459_000_000); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalDateTime.of(2012, 9, 16, 22, 17, 59, 459_000_000), bytes); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void constant_MIN() { + check(LocalDateTime.MIN, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0); + } + + @Test + public void constant_MAX() { + check(LocalDateTime.MAX, Year.MAX_VALUE, 12, 31, 23, 59, 59, 999999999); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(timeOut=30000, groups={"tck"}) // TODO: remove when time zone loading is faster + public void now() { + LocalDateTime expected = LocalDateTime.now(Clock.systemDefaultZone()); + LocalDateTime test = LocalDateTime.now(); + long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().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()); + } + assertTrue(diff < 100000000); // less than 0.1 secs + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + LocalDateTime.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + LocalDateTime expected = LocalDateTime.now(Clock.system(zone)); + LocalDateTime test = LocalDateTime.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = LocalDateTime.now(Clock.system(zone)); + test = LocalDateTime.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + LocalDateTime.now((Clock) null); + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_utc() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + LocalDateTime test = LocalDateTime.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2)); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 123456789); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_offset() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE); + LocalDateTime test = LocalDateTime.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 123456789); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_beforeEpoch() { + LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L); + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + LocalDateTime test = LocalDateTime.now(clock); + assertEquals(test.getYear(), 1969); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + expected = expected.minusSeconds(1); + assertEquals(test.getTime(), expected); + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock_maxYear() { + Clock clock = Clock.fixed(MAX_INSTANT, ZoneOffset.UTC); + LocalDateTime test = LocalDateTime.now(clock); + assertEquals(test, MAX_DATE_TIME); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void now_Clock_tooBig() { + Clock clock = Clock.fixed(MAX_INSTANT.plusSeconds(24 * 60 * 60), ZoneOffset.UTC); + LocalDateTime.now(clock); + } + + @Test(groups={"tck"}) + public void now_Clock_minYear() { + Clock clock = Clock.fixed(MIN_INSTANT, ZoneOffset.UTC); + LocalDateTime test = LocalDateTime.now(clock); + assertEquals(test, MIN_DATE_TIME); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void now_Clock_tooLow() { + Clock clock = Clock.fixed(MIN_INSTANT.minusNanos(1), ZoneOffset.UTC); + LocalDateTime.now(clock); + } + + //----------------------------------------------------------------------- + // of() factories + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_4intsMonth() { + LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30); + check(dateTime, 2007, 7, 15, 12, 30, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_4intsMonth_nullMonth() { + LocalDateTime.of(2007, null, 15, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_dayTooLow() { + LocalDateTime.of(2007, Month.JULY, -1, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_dayTooHigh() { + LocalDateTime.of(2007, Month.JULY, 32, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_hourTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, -1, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_hourTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 24, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_minuteTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_4intsMonth_minuteTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_5intsMonth() { + LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40); + check(dateTime, 2007, 7, 15, 12, 30, 40, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30, 40); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_5intsMonth_nullMonth() { + LocalDateTime.of(2007, null, 15, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_dayTooLow() { + LocalDateTime.of(2007, Month.JULY, -1, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_dayTooHigh() { + LocalDateTime.of(2007, Month.JULY, 32, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_hourTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, -1, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_hourTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 24, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_minuteTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, -1, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_minuteTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 60, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_secondTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5intsMonth_secondTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_6intsMonth() { + LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, 987654321); + check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_6intsMonth_nullMonth() { + LocalDateTime.of(2007, null, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_dayTooLow() { + LocalDateTime.of(2007, Month.JULY, -1, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_dayTooHigh() { + LocalDateTime.of(2007, Month.JULY, 32, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_hourTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, -1, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_hourTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 24, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_minuteTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, -1, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_minuteTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 60, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_secondTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, -1, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_secondTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 60, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_nanoTooLow() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6intsMonth_nanoTooHigh() { + LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, 1000000000); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_5ints() { + LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30); + check(dateTime, 2007, 7, 15, 12, 30, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_monthTooLow() { + LocalDateTime.of(2007, 0, 15, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_monthTooHigh() { + LocalDateTime.of(2007, 13, 15, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_dayTooLow() { + LocalDateTime.of(2007, 7, -1, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_dayTooHigh() { + LocalDateTime.of(2007, 7, 32, 12, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_hourTooLow() { + LocalDateTime.of(2007, 7, 15, -1, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_hourTooHigh() { + LocalDateTime.of(2007, 7, 15, 24, 30); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_minuteTooLow() { + LocalDateTime.of(2007, 7, 15, 12, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_5ints_minuteTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_6ints() { + LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30, 40); + check(dateTime, 2007, 7, 15, 12, 30, 40, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_monthTooLow() { + LocalDateTime.of(2007, 0, 15, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_monthTooHigh() { + LocalDateTime.of(2007, 13, 15, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_dayTooLow() { + LocalDateTime.of(2007, 7, -1, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_dayTooHigh() { + LocalDateTime.of(2007, 7, 32, 12, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_hourTooLow() { + LocalDateTime.of(2007, 7, 15, -1, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_hourTooHigh() { + LocalDateTime.of(2007, 7, 15, 24, 30, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_minuteTooLow() { + LocalDateTime.of(2007, 7, 15, 12, -1, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_minuteTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 60, 40); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_secondTooLow() { + LocalDateTime.of(2007, 7, 15, 12, 30, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_6ints_secondTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 30, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_7ints() { + LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321); + check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_yearTooLow() { + LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_monthTooLow() { + LocalDateTime.of(2007, 0, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_monthTooHigh() { + LocalDateTime.of(2007, 13, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_dayTooLow() { + LocalDateTime.of(2007, 7, -1, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_dayTooHigh() { + LocalDateTime.of(2007, 7, 32, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_hourTooLow() { + LocalDateTime.of(2007, 7, 15, -1, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_hourTooHigh() { + LocalDateTime.of(2007, 7, 15, 24, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_minuteTooLow() { + LocalDateTime.of(2007, 7, 15, 12, -1, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_minuteTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 60, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_secondTooLow() { + LocalDateTime.of(2007, 7, 15, 12, 30, -1, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_secondTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 30, 60, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_nanoTooLow() { + LocalDateTime.of(2007, 7, 15, 12, 30, 40, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_of_7ints_nanoTooHigh() { + LocalDateTime.of(2007, 7, 15, 12, 30, 40, 1000000000); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_LocalDate_LocalTime() { + LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(12, 30, 40, 987654321)); + check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDate_LocalTime_nullLocalDate() { + LocalDateTime.of(null, LocalTime.of(12, 30, 40, 987654321)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDate_LocalTime_nullLocalTime() { + LocalDateTime.of(LocalDate.of(2007, 7, 15), null); + } + + //----------------------------------------------------------------------- + // ofInstant() + //----------------------------------------------------------------------- + @DataProvider(name="instantFactory") + Object[][] data_instantFactory() { + return new Object[][] { + {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), ZONE_PARIS, LocalDateTime.of(1970, 1, 2, 2, 2, 4, 500)}, + {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), OFFSET_MTWO, LocalDateTime.of(1970, 1, 1, 23, 2, 4, 500)}, + {Instant.ofEpochSecond(-86400 + 4, 500), OFFSET_PTWO, LocalDateTime.of(1969, 12, 31, 2, 0, 4, 500)}, + {OffsetDateTime.of(LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0), ZoneOffset.UTC).toInstant(), + ZoneOffset.UTC, LocalDateTime.MIN}, + {OffsetDateTime.of(LocalDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 59, 999_999_999), ZoneOffset.UTC).toInstant(), + ZoneOffset.UTC, LocalDateTime.MAX}, + }; + } + + @Test(dataProvider="instantFactory") + public void factory_ofInstant(Instant instant, ZoneId zone, LocalDateTime expected) { + LocalDateTime test = LocalDateTime.ofInstant(instant, zone); + assertEquals(test, expected); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_instantTooBig() { + LocalDateTime.ofInstant(Instant.MAX, OFFSET_PONE) ; + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_instantTooSmall() { + LocalDateTime.ofInstant(Instant.MIN, OFFSET_PONE) ; + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_nullInstant() { + LocalDateTime.ofInstant((Instant) null, ZONE_GAZA); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_nullZone() { + LocalDateTime.ofInstant(Instant.EPOCH, (ZoneId) null); + } + + //----------------------------------------------------------------------- + // ofEpochSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofEpochSecond_longOffset_afterEpoch() { + LocalDateTime base = LocalDateTime.of(1970, 1, 1, 2, 0, 0, 500); + for (int i = 0; i < 100000; i++) { + LocalDateTime test = LocalDateTime.ofEpochSecond(i, 500, OFFSET_PTWO); + assertEquals(test, base.plusSeconds(i)); + } + } + + @Test(groups={"tck"}) + public void factory_ofEpochSecond_longOffset_beforeEpoch() { + LocalDateTime base = LocalDateTime.of(1970, 1, 1, 2, 0, 0, 500); + for (int i = 0; i < 100000; i++) { + LocalDateTime test = LocalDateTime.ofEpochSecond(-i, 500, OFFSET_PTWO); + assertEquals(test, base.minusSeconds(i)); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochSecond_longOffset_tooBig() { + LocalDateTime.ofEpochSecond(Long.MAX_VALUE, 500, OFFSET_PONE); // TODO: better test + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochSecond_longOffset_tooSmall() { + LocalDateTime.ofEpochSecond(Long.MIN_VALUE, 500, OFFSET_PONE); // TODO: better test + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochSecond_badNanos_toBig() { + LocalDateTime.ofEpochSecond(0, 1_000_000_000, OFFSET_PONE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofEpochSecond_badNanos_toSmall() { + LocalDateTime.ofEpochSecond(0, -1, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofEpochSecond_longOffset_nullOffset() { + LocalDateTime.ofEpochSecond(0L, 500, null); + } + + //----------------------------------------------------------------------- + // from() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_from_TemporalAccessor() { + LocalDateTime base = LocalDateTime.of(2007, 7, 15, 17, 30); + assertEquals(LocalDateTime.from(base), base); + assertEquals(LocalDateTime.from(ZonedDateTime.of(base, ZoneOffset.ofHours(2))), base); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_from_TemporalAccessor_invalid_noDerive() { + LocalDateTime.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_from_TemporalAccessor_null() { + LocalDateTime.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_parse(int y, int month, int d, int h, int m, int s, int n, String text) { + LocalDateTime t = LocalDateTime.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); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue() { + LocalDateTime.parse("2008-06-32T11:15"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_invalidValue() { + LocalDateTime.parse("2008-06-31T11:15"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + LocalDateTime.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + LocalDateTime.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + LocalDateTime.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + LocalDateTime test = LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321); + 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.HOUR_OF_DAY), 12); + assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1); + } + + @Test + public void test_getLong_TemporalField() { + LocalDateTime test = LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321); + 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.HOUR_OF_DAY), 12); + assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_2007_07_15_12_30_40_987654321.query(null); + } + + //----------------------------------------------------------------------- + @DataProvider(name="sampleDates") + Object[][] provider_sampleDates() { + return new Object[][] { + {2008, 7, 5}, + {2007, 7, 5}, + {2006, 7, 5}, + {2005, 7, 5}, + {2004, 1, 1}, + {-1, 1, 2}, + }; + } + + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {0, 0, 0, 0}, + {0, 0, 0, 1}, + {0, 0, 1, 0}, + {0, 0, 1, 1}, + {0, 1, 0, 0}, + {0, 1, 0, 1}, + {0, 1, 1, 0}, + {0, 1, 1, 1}, + {1, 0, 0, 0}, + {1, 0, 0, 1}, + {1, 0, 1, 0}, + {1, 0, 1, 1}, + {1, 1, 0, 0}, + {1, 1, 0, 1}, + {1, 1, 1, 0}, + {1, 1, 1, 1}, + }; + } + + //----------------------------------------------------------------------- + // get*() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_get_dates(int y, int m, int d) { + LocalDateTime a = LocalDateTime.of(y, m, d, 12, 30); + assertEquals(a.getYear(), y); + assertEquals(a.getMonth(), Month.of(m)); + assertEquals(a.getDayOfMonth(), d); + } + + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_getDOY(int y, int m, int d) { + LocalDateTime a = LocalDateTime.of(y, m, d, 12 ,30); + int total = 0; + for (int i = 1; i < m; i++) { + total += Month.of(i).length(isIsoLeap(y)); + } + int doy = total + d; + assertEquals(a.getDayOfYear(), doy); + } + + @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)); + assertEquals(a.getHour(), h); + assertEquals(a.getMinute(), m); + assertEquals(a.getSecond(), s); + assertEquals(a.getNano(), ns); + } + + //----------------------------------------------------------------------- + // getDayOfWeek() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getDayOfWeek() { + DayOfWeek dow = DayOfWeek.MONDAY; + for (Month month : Month.values()) { + 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()); + assertSame(d.getDayOfWeek(), dow); + dow = dow.plus(1); + } + } + } + + //----------------------------------------------------------------------- + // with() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_adjustment() { + final LocalDateTime sample = LocalDateTime.of(2012, 3, 4, 23, 5); + TemporalAdjuster adjuster = new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return sample; + } + }; + assertEquals(TEST_2007_07_15_12_30_40_987654321.with(adjuster), sample); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_adjustment_null() { + TEST_2007_07_15_12_30_40_987654321.with((TemporalAdjuster) null); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withYear(2008); + check(t, 2008, 7, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withYear_int_invalid() { + TEST_2007_07_15_12_30_40_987654321.withYear(Year.MIN_VALUE - 1); + } + + @Test(groups={"tck"}) + public void test_withYear_int_adjustDay() { + LocalDateTime t = LocalDateTime.of(2008, 2, 29, 12, 30).withYear(2007); + LocalDateTime expected = LocalDateTime.of(2007, 2, 28, 12, 30); + assertEquals(t, expected); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMonth(1); + check(t, 2007, 1, 15, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_int_invalid() { + TEST_2007_07_15_12_30_40_987654321.withMonth(13); + } + + @Test(groups={"tck"}) + public void test_withMonth_int_adjustDay() { + LocalDateTime t = LocalDateTime.of(2007, 12, 31, 12, 30).withMonth(11); + LocalDateTime expected = LocalDateTime.of(2007, 11, 30, 12, 30); + assertEquals(t, expected); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfMonth_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfMonth(1); + check(t, 2007, 7, 1, 12, 30, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_invalid() { + LocalDateTime.of(2007, 11, 30, 12, 30).withDayOfMonth(32); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_invalidCombination() { + LocalDateTime.of(2007, 11, 30, 12, 30).withDayOfMonth(31); + } + + //----------------------------------------------------------------------- + // withDayOfYear(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfYear_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfYear(33); + assertEquals(t, LocalDateTime.of(2007, 2, 2, 12, 30, 40, 987654321)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_illegal() { + TEST_2007_07_15_12_30_40_987654321.withDayOfYear(367); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_invalid() { + TEST_2007_07_15_12_30_40_987654321.withDayOfYear(366); + } + + //----------------------------------------------------------------------- + // withHour() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withHour_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321; + for (int i = 0; i < 24; i++) { + t = t.withHour(i); + assertEquals(t.getHour(), i); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withHour_hourTooLow() { + TEST_2007_07_15_12_30_40_987654321.withHour(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withHour_hourTooHigh() { + TEST_2007_07_15_12_30_40_987654321.withHour(24); + } + + //----------------------------------------------------------------------- + // withMinute() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMinute_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321; + for (int i = 0; i < 60; i++) { + t = t.withMinute(i); + assertEquals(t.getMinute(), i); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMinute_minuteTooLow() { + TEST_2007_07_15_12_30_40_987654321.withMinute(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMinute_minuteTooHigh() { + TEST_2007_07_15_12_30_40_987654321.withMinute(60); + } + + //----------------------------------------------------------------------- + // withSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withSecond_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321; + for (int i = 0; i < 60; i++) { + t = t.withSecond(i); + assertEquals(t.getSecond(), i); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withSecond_secondTooLow() { + TEST_2007_07_15_12_30_40_987654321.withSecond(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withSecond_secondTooHigh() { + TEST_2007_07_15_12_30_40_987654321.withSecond(60); + } + + //----------------------------------------------------------------------- + // withNano() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withNanoOfSecond_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321; + t = t.withNano(1); + assertEquals(t.getNano(), 1); + t = t.withNano(10); + assertEquals(t.getNano(), 10); + t = t.withNano(100); + assertEquals(t.getNano(), 100); + t = t.withNano(999999999); + assertEquals(t.getNano(), 999999999); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withNanoOfSecond_nanoTooLow() { + TEST_2007_07_15_12_30_40_987654321.withNano(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withNanoOfSecond_nanoTooHigh() { + TEST_2007_07_15_12_30_40_987654321.withNano(1000000000); + } + + //----------------------------------------------------------------------- + // truncatedTo(TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_truncatedTo_normal() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(NANOS), TEST_2007_07_15_12_30_40_987654321); + assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(SECONDS), TEST_2007_07_15_12_30_40_987654321.withNano(0)); + assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(DAYS), TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_2007_07_15_12_30_40_987654321.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus(adjuster) + //----------------------------------------------------------------------- + @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); + 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); + 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); + 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); + LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).plus(period); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_positiveMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(7, ChronoUnit.MONTHS); + assertEquals(t, LocalDateTime.of(2008, 2, 15, 12, 30, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_negativeDays() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(-25, ChronoUnit.DAYS); + assertEquals(t, LocalDateTime.of(2007, 6, 20, 12, 30, 40, 987654321)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_null() { + TEST_2007_07_15_12_30_40_987654321.plus(1, (TemporalUnit) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_invalidTooLarge() { + LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).plus(1, ChronoUnit.YEARS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_invalidTooSmall() { + LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).plus(-1, ChronoUnit.YEARS); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(1); + check(t, 2008, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusYears_int_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1); + check(t, 2006, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusYears_int_adjustDay() { + LocalDateTime t = createDateMidnight(2008, 2, 29).plusYears(1); + check(t, 2009, 2, 28, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_int_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 1, 1).plusYears(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_int_invalidTooSmall() { + LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-1); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMonths_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(1); + check(t, 2007, 8, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_overYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(25); + check(t, 2009, 8, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-1); + check(t, 2007, 6, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-7); + check(t, 2006, 12, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-31); + check(t, 2004, 12, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_adjustDayFromLeapYear() { + LocalDateTime t = createDateMidnight(2008, 2, 29).plusMonths(12); + check(t, 2009, 2, 28, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_plusMonths_int_adjustDayFromMonthLength() { + LocalDateTime t = createDateMidnight(2007, 3, 31).plusMonths(1); + check(t, 2007, 4, 30, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_int_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 1).plusMonths(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_int_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).plusMonths(-1); + } + + //----------------------------------------------------------------------- + // plusWeeks() + //----------------------------------------------------------------------- + @DataProvider(name="samplePlusWeeksSymmetry") + Object[][] provider_samplePlusWeeksSymmetry() { + return new Object[][] { + {createDateMidnight(-1, 1, 1)}, + {createDateMidnight(-1, 2, 28)}, + {createDateMidnight(-1, 3, 1)}, + {createDateMidnight(-1, 12, 31)}, + {createDateMidnight(0, 1, 1)}, + {createDateMidnight(0, 2, 28)}, + {createDateMidnight(0, 2, 29)}, + {createDateMidnight(0, 3, 1)}, + {createDateMidnight(0, 12, 31)}, + {createDateMidnight(2007, 1, 1)}, + {createDateMidnight(2007, 2, 28)}, + {createDateMidnight(2007, 3, 1)}, + {createDateMidnight(2007, 12, 31)}, + {createDateMidnight(2008, 1, 1)}, + {createDateMidnight(2008, 2, 28)}, + {createDateMidnight(2008, 2, 29)}, + {createDateMidnight(2008, 3, 1)}, + {createDateMidnight(2008, 12, 31)}, + {createDateMidnight(2099, 1, 1)}, + {createDateMidnight(2099, 2, 28)}, + {createDateMidnight(2099, 3, 1)}, + {createDateMidnight(2099, 12, 31)}, + {createDateMidnight(2100, 1, 1)}, + {createDateMidnight(2100, 2, 28)}, + {createDateMidnight(2100, 3, 1)}, + {createDateMidnight(2100, 12, 31)}, + }; + } + + @Test(dataProvider="samplePlusWeeksSymmetry", groups={"tck"}) + public void test_plusWeeks_symmetry(LocalDateTime reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + LocalDateTime 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() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(1); + check(t, 2007, 7, 22, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(9); + check(t, 2007, 9, 16, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overYears() { + LocalDateTime t = LocalDateTime.of(2006, 7, 16, 12, 30, 40, 987654321).plusWeeks(52); + assertEquals(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_overLeapYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1).plusWeeks(104); + check(t, 2008, 7, 12, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-1); + check(t, 2007, 7, 8, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-28); + check(t, 2006, 12, 31, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-104); + check(t, 2005, 7, 17, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_maximum() { + LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 24).plusWeeks(1); + check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_minimum() { + LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 8).plusWeeks(-1); + check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusWeeks_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 25).plusWeeks(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusWeeks_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 7).plusWeeks(-1); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + @DataProvider(name="samplePlusDaysSymmetry") + Object[][] provider_samplePlusDaysSymmetry() { + return new Object[][] { + {createDateMidnight(-1, 1, 1)}, + {createDateMidnight(-1, 2, 28)}, + {createDateMidnight(-1, 3, 1)}, + {createDateMidnight(-1, 12, 31)}, + {createDateMidnight(0, 1, 1)}, + {createDateMidnight(0, 2, 28)}, + {createDateMidnight(0, 2, 29)}, + {createDateMidnight(0, 3, 1)}, + {createDateMidnight(0, 12, 31)}, + {createDateMidnight(2007, 1, 1)}, + {createDateMidnight(2007, 2, 28)}, + {createDateMidnight(2007, 3, 1)}, + {createDateMidnight(2007, 12, 31)}, + {createDateMidnight(2008, 1, 1)}, + {createDateMidnight(2008, 2, 28)}, + {createDateMidnight(2008, 2, 29)}, + {createDateMidnight(2008, 3, 1)}, + {createDateMidnight(2008, 12, 31)}, + {createDateMidnight(2099, 1, 1)}, + {createDateMidnight(2099, 2, 28)}, + {createDateMidnight(2099, 3, 1)}, + {createDateMidnight(2099, 12, 31)}, + {createDateMidnight(2100, 1, 1)}, + {createDateMidnight(2100, 2, 28)}, + {createDateMidnight(2100, 3, 1)}, + {createDateMidnight(2100, 12, 31)}, + }; + } + + @Test(dataProvider="samplePlusDaysSymmetry", groups={"tck"}) + public void test_plusDays_symmetry(LocalDateTime reference) { + for (int days = 0; days < 365 * 8; days++) { + LocalDateTime 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() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(1); + check(t, 2007, 7, 16, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_overMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(62); + check(t, 2007, 9, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_overYears() { + LocalDateTime t = LocalDateTime.of(2006, 7, 14, 12, 30, 40, 987654321).plusDays(366); + assertEquals(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_overLeapYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1).plusDays(365 + 366); + check(t, 2008, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-1); + check(t, 2007, 7, 14, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-196); + check(t, 2006, 12, 31, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-730); + check(t, 2005, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_plusDays_maximum() { + LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 30).plusDays(1); + check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_plusDays_minimum() { + LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 2).plusDays(-1); + check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusDays_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 31).plusDays(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusDays_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).plusDays(-1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_plusDays_overflowTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 31).plusDays(Long.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_plusDays_overflowTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).plusDays(Long.MIN_VALUE); + } + + //----------------------------------------------------------------------- + // plusHours() + //----------------------------------------------------------------------- + @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(); + + for (int i = 0; i < 50; i++) { + t = t.plusHours(1); + + if ((i + 1) % 24 == 0) { + d = d.plusDays(1); + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), (i + 1) % 24); + } + } + + @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); + LocalTime t = LocalTime.of(21, 0); + + for (int i = -50; i < 50; i++) { + LocalDateTime dt = base.plusHours(i); + t = t.plusHours(1); + + if (t.getHour() == 0) { + d = d.plusDays(1); + } + + assertEquals(dt.getDate(), d); + assertEquals(dt.getTime(), 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); + LocalTime t = LocalTime.of(22, 0); + + for (int i = -50; i < 50; i++) { + LocalDateTime dt = base.plusHours(i); + + t = t.plusHours(1); + + if (t.getHour() == 0) { + d = d.plusDays(1); + } + + assertEquals(dt.getDate(), d); + assertEquals(dt.getTime(), t); + } + } + + //----------------------------------------------------------------------- + // plusMinutes() + //----------------------------------------------------------------------- + @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(); + + int hour = 0; + int min = 0; + + for (int i = 0; i < 70; i++) { + t = t.plusMinutes(1); + min++; + if (min == 60) { + hour++; + min = 0; + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @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); + LocalTime t = LocalTime.of(22, 49); + + for (int i = -70; i < 70; i++) { + LocalDateTime dt = base.plusMinutes(i); + t = t.plusMinutes(1); + + if (t == LocalTime.MIDNIGHT) { + d = d.plusDays(1); + } + + assertEquals(dt.getDate(), d, String.valueOf(i)); + assertEquals(dt.getTime(), 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)); + } + + //----------------------------------------------------------------------- + // plusSeconds() + //----------------------------------------------------------------------- + @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(); + + int hour = 0; + int min = 0; + int sec = 0; + + for (int i = 0; i < 3700; i++) { + t = t.plusSeconds(1); + sec++; + if (sec == 60) { + min++; + sec = 0; + } + if (min == 60) { + hour++; + min = 0; + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + } + } + + @DataProvider(name="plusSeconds_fromZero") + Iterator plusSeconds_fromZero() { + return new Iterator() { + int delta = 30; + + int i = -3660; + LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + int hour = 22; + int min = 59; + int sec = 0; + + public boolean hasNext() { + return i <= 3660; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, date, hour, min, sec}; + i += delta; + sec += delta; + + if (sec >= 60) { + min++; + sec -= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + + if (i == 0) { + date = date.plusDays(1); + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="plusSeconds_fromZero", groups={"tck"}) + public void test_plusSeconds_fromZero(int seconds, LocalDate date, int hour, int min, int sec) { + LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); + LocalDateTime t = base.plusSeconds(seconds); + + assertEquals(date, t.getDate()); + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + } + + @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)); + } + + //----------------------------------------------------------------------- + // plusNanos() + //----------------------------------------------------------------------- + @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(); + + int hour = 0; + int min = 0; + int sec = 0; + int nanos = 0; + + for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) { + t = t.plusNanos(500000000); + nanos += 500000000; + if (nanos == 1000000000) { + sec++; + nanos = 0; + } + if (sec == 60) { + min++; + sec = 0; + } + if (min == 60) { + hour++; + min = 0; + } + + assertEquals(t.getDate(), d, String.valueOf(i)); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + assertEquals(t.getNano(), nanos); + } + } + + @DataProvider(name="plusNanos_fromZero") + Iterator plusNanos_fromZero() { + return new Iterator() { + long delta = 7500000000L; + + long i = -3660 * 1000000000L; + LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + int hour = 22; + int min = 59; + int sec = 0; + long nanos = 0; + + public boolean hasNext() { + return i <= 3660 * 1000000000L; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, date, hour, min, sec, (int)nanos}; + i += delta; + nanos += delta; + + if (nanos >= 1000000000L) { + sec += nanos / 1000000000L; + nanos %= 1000000000L; + + if (sec >= 60) { + min++; + sec %= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + date = date.plusDays(1); + } + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="plusNanos_fromZero", groups={"tck"}) + public void test_plusNanos_fromZero(long nanoseconds, LocalDate date, int hour, int min, int sec, int nanos) { + LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); + LocalDateTime t = base.plusNanos(nanoseconds); + + assertEquals(date, t.getDate()); + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + assertEquals(nanos, t.getNano()); + } + + @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)); + } + + //----------------------------------------------------------------------- + // minus(adjuster) + //----------------------------------------------------------------------- + @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); + 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); + 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); + 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); + LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).minus(period); + } + + //----------------------------------------------------------------------- + // minus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_positiveMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(7, ChronoUnit.MONTHS); + assertEquals(t, LocalDateTime.of(2006, 12, 15, 12, 30, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_negativeDays() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(-25, ChronoUnit.DAYS); + assertEquals(t, LocalDateTime.of(2007, 8, 9, 12, 30, 40, 987654321)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_null() { + TEST_2007_07_15_12_30_40_987654321.minus(1, (TemporalUnit) null); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_invalidTooLarge() { + LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).minus(-1, ChronoUnit.YEARS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_invalidTooSmall() { + LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).minus(1, ChronoUnit.YEARS); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(1); + check(t, 2006, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusYears_int_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(-1); + check(t, 2008, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusYears_int_adjustDay() { + LocalDateTime t = createDateMidnight(2008, 2, 29).minusYears(1); + check(t, 2007, 2, 28, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_int_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 1, 1).minusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_int_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).minusYears(1); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMonths_int_normal() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(1); + check(t, 2007, 6, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_overYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(25); + check(t, 2005, 6, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-1); + check(t, 2007, 8, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-7); + check(t, 2008, 2, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-31); + check(t, 2010, 2, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_adjustDayFromLeapYear() { + LocalDateTime t = createDateMidnight(2008, 2, 29).minusMonths(12); + check(t, 2007, 2, 28, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_minusMonths_int_adjustDayFromMonthLength() { + LocalDateTime t = createDateMidnight(2007, 3, 31).minusMonths(1); + check(t, 2007, 2, 28, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_int_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 1).minusMonths(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_int_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).minusMonths(1); + } + + //----------------------------------------------------------------------- + // minusWeeks() + //----------------------------------------------------------------------- + @DataProvider(name="sampleMinusWeeksSymmetry") + Object[][] provider_sampleMinusWeeksSymmetry() { + return new Object[][] { + {createDateMidnight(-1, 1, 1)}, + {createDateMidnight(-1, 2, 28)}, + {createDateMidnight(-1, 3, 1)}, + {createDateMidnight(-1, 12, 31)}, + {createDateMidnight(0, 1, 1)}, + {createDateMidnight(0, 2, 28)}, + {createDateMidnight(0, 2, 29)}, + {createDateMidnight(0, 3, 1)}, + {createDateMidnight(0, 12, 31)}, + {createDateMidnight(2007, 1, 1)}, + {createDateMidnight(2007, 2, 28)}, + {createDateMidnight(2007, 3, 1)}, + {createDateMidnight(2007, 12, 31)}, + {createDateMidnight(2008, 1, 1)}, + {createDateMidnight(2008, 2, 28)}, + {createDateMidnight(2008, 2, 29)}, + {createDateMidnight(2008, 3, 1)}, + {createDateMidnight(2008, 12, 31)}, + {createDateMidnight(2099, 1, 1)}, + {createDateMidnight(2099, 2, 28)}, + {createDateMidnight(2099, 3, 1)}, + {createDateMidnight(2099, 12, 31)}, + {createDateMidnight(2100, 1, 1)}, + {createDateMidnight(2100, 2, 28)}, + {createDateMidnight(2100, 3, 1)}, + {createDateMidnight(2100, 12, 31)}, + }; + } + + @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"tck"}) + public void test_minusWeeks_symmetry(LocalDateTime reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + LocalDateTime 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() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(1); + check(t, 2007, 7, 8, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(9); + check(t, 2007, 5, 13, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overYears() { + LocalDateTime t = LocalDateTime.of(2008, 7, 13, 12, 30, 40, 987654321).minusWeeks(52); + assertEquals(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_overLeapYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(-1).minusWeeks(104); + check(t, 2006, 7, 18, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-1); + check(t, 2007, 7, 22, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-28); + check(t, 2008, 1, 27, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-104); + check(t, 2009, 7, 12, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_maximum() { + LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 24).minusWeeks(-1); + check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_minimum() { + LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 8).minusWeeks(1); + check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusWeeks_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 25).minusWeeks(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusWeeks_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 7).minusWeeks(1); + } + + //----------------------------------------------------------------------- + // minusDays() + //----------------------------------------------------------------------- + @DataProvider(name="sampleMinusDaysSymmetry") + Object[][] provider_sampleMinusDaysSymmetry() { + return new Object[][] { + {createDateMidnight(-1, 1, 1)}, + {createDateMidnight(-1, 2, 28)}, + {createDateMidnight(-1, 3, 1)}, + {createDateMidnight(-1, 12, 31)}, + {createDateMidnight(0, 1, 1)}, + {createDateMidnight(0, 2, 28)}, + {createDateMidnight(0, 2, 29)}, + {createDateMidnight(0, 3, 1)}, + {createDateMidnight(0, 12, 31)}, + {createDateMidnight(2007, 1, 1)}, + {createDateMidnight(2007, 2, 28)}, + {createDateMidnight(2007, 3, 1)}, + {createDateMidnight(2007, 12, 31)}, + {createDateMidnight(2008, 1, 1)}, + {createDateMidnight(2008, 2, 28)}, + {createDateMidnight(2008, 2, 29)}, + {createDateMidnight(2008, 3, 1)}, + {createDateMidnight(2008, 12, 31)}, + {createDateMidnight(2099, 1, 1)}, + {createDateMidnight(2099, 2, 28)}, + {createDateMidnight(2099, 3, 1)}, + {createDateMidnight(2099, 12, 31)}, + {createDateMidnight(2100, 1, 1)}, + {createDateMidnight(2100, 2, 28)}, + {createDateMidnight(2100, 3, 1)}, + {createDateMidnight(2100, 12, 31)}, + }; + } + + @Test(dataProvider="sampleMinusDaysSymmetry", groups={"tck"}) + public void test_minusDays_symmetry(LocalDateTime reference) { + for (int days = 0; days < 365 * 8; days++) { + LocalDateTime 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() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(1); + check(t, 2007, 7, 14, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_overMonths() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(62); + check(t, 2007, 5, 14, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_overYears() { + LocalDateTime t = LocalDateTime.of(2008, 7, 16, 12, 30, 40, 987654321).minusDays(367); + assertEquals(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_overLeapYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(2).minusDays(365 + 366); + assertEquals(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_negative() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-1); + check(t, 2007, 7, 16, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_negativeAcrossYear() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-169); + check(t, 2007, 12, 31, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_negativeOverYears() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-731); + check(t, 2009, 7, 15, 12, 30, 40, 987654321); + } + + @Test(groups={"tck"}) + public void test_minusDays_maximum() { + LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 30).minusDays(-1); + check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0); + } + + @Test(groups={"tck"}) + public void test_minusDays_minimum() { + LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 2).minusDays(1); + check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusDays_invalidTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 31).minusDays(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusDays_invalidTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).minusDays(1); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_minusDays_overflowTooLarge() { + createDateMidnight(Year.MAX_VALUE, 12, 31).minusDays(Long.MIN_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) + public void test_minusDays_overflowTooSmall() { + createDateMidnight(Year.MIN_VALUE, 1, 1).minusDays(Long.MAX_VALUE); + } + + //----------------------------------------------------------------------- + // minusHours() + //----------------------------------------------------------------------- + @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(); + + for (int i = 0; i < 50; i++) { + t = t.minusHours(1); + + if (i % 24 == 0) { + d = d.minusDays(1); + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), (((-i + 23) % 24) + 24) % 24); + } + } + + @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); + LocalTime t = LocalTime.of(3, 0); + + for (int i = -50; i < 50; i++) { + LocalDateTime dt = base.minusHours(i); + t = t.minusHours(1); + + if (t.getHour() == 23) { + d = d.minusDays(1); + } + + assertEquals(dt.getDate(), d, String.valueOf(i)); + assertEquals(dt.getTime(), 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); + LocalTime t = LocalTime.of(4, 0); + + for (int i = -50; i < 50; i++) { + LocalDateTime dt = base.minusHours(i); + + t = t.minusHours(1); + + if (t.getHour() == 23) { + d = d.minusDays(1); + } + + assertEquals(dt.getDate(), d, String.valueOf(i)); + assertEquals(dt.getTime(), t); + } + } + + //----------------------------------------------------------------------- + // minusMinutes() + //----------------------------------------------------------------------- + @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); + + int hour = 0; + int min = 0; + + for (int i = 0; i < 70; i++) { + t = t.minusMinutes(1); + min--; + if (min == -1) { + hour--; + min = 59; + + if (hour == -1) { + hour = 23; + } + } + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @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); + LocalTime t = LocalTime.of(22, 49); + + for (int i = 70; i > -70; i--) { + LocalDateTime dt = base.minusMinutes(i); + t = t.plusMinutes(1); + + if (t == LocalTime.MIDNIGHT) { + d = d.plusDays(1); + } + + assertEquals(dt.getDate(), d); + assertEquals(dt.getTime(), 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)); + } + + //----------------------------------------------------------------------- + // minusSeconds() + //----------------------------------------------------------------------- + @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); + + int hour = 0; + int min = 0; + int sec = 0; + + for (int i = 0; i < 3700; i++) { + t = t.minusSeconds(1); + sec--; + if (sec == -1) { + min--; + sec = 59; + + if (min == -1) { + hour--; + min = 59; + + if (hour == -1) { + hour = 23; + } + } + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + } + } + + @DataProvider(name="minusSeconds_fromZero") + Iterator minusSeconds_fromZero() { + return new Iterator() { + int delta = 30; + + int i = 3660; + LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + int hour = 22; + int min = 59; + int sec = 0; + + public boolean hasNext() { + return i >= -3660; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, date, hour, min, sec}; + i -= delta; + sec += delta; + + if (sec >= 60) { + min++; + sec -= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + + if (i == 0) { + date = date.plusDays(1); + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="minusSeconds_fromZero", groups={"tck"}) + public void test_minusSeconds_fromZero(int seconds, LocalDate date, int hour, int min, int sec) { + LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); + LocalDateTime t = base.minusSeconds(seconds); + + assertEquals(date, t.getDate()); + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + } + + //----------------------------------------------------------------------- + // minusNanos() + //----------------------------------------------------------------------- + @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); + + int hour = 0; + int min = 0; + int sec = 0; + int nanos = 0; + + for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) { + t = t.minusNanos(500000000); + nanos -= 500000000; + + if (nanos < 0) { + sec--; + nanos += 1000000000; + + if (sec == -1) { + min--; + sec += 60; + + if (min == -1) { + hour--; + min += 60; + + if (hour == -1) { + hour += 24; + } + } + } + } + + assertEquals(t.getDate(), d); + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + assertEquals(t.getNano(), nanos); + } + } + + @DataProvider(name="minusNanos_fromZero") + Iterator minusNanos_fromZero() { + return new Iterator() { + long delta = 7500000000L; + + long i = 3660 * 1000000000L; + LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + int hour = 22; + int min = 59; + int sec = 0; + long nanos = 0; + + public boolean hasNext() { + return i >= -3660 * 1000000000L; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, date, hour, min, sec, (int)nanos}; + i -= delta; + nanos += delta; + + if (nanos >= 1000000000L) { + sec += nanos / 1000000000L; + nanos %= 1000000000L; + + if (sec >= 60) { + min++; + sec %= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + date = date.plusDays(1); + } + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="minusNanos_fromZero", groups={"tck"}) + public void test_minusNanos_fromZero(long nanoseconds, LocalDate date, int hour, int min, int sec, int nanos) { + LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); + LocalDateTime t = base.minusNanos(nanoseconds); + + assertEquals(date, t.getDate()); + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + assertEquals(nanos, t.getNano()); + } + + //----------------------------------------------------------------------- + // atOffset() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atOffset() { + LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30); + assertEquals(t.atOffset(OFFSET_PTWO), OffsetDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PTWO)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atOffset_nullZoneOffset() { + LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30); + t.atOffset((ZoneOffset) null); + } + + //----------------------------------------------------------------------- + // atZone() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atZone() { + LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30); + assertEquals(t.atZone(ZONE_PARIS), + ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), ZONE_PARIS)); + } + + @Test(groups={"tck"}) + public void test_atZone_Offset() { + LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30); + assertEquals(t.atZone(OFFSET_PTWO), ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PTWO)); + } + + @Test(groups={"tck"}) + public void test_atZone_dstGap() { + LocalDateTime t = LocalDateTime.of(2007, 4, 1, 0, 0); + assertEquals(t.atZone(ZONE_GAZA), + ZonedDateTime.of(LocalDateTime.of(2007, 4, 1, 1, 0), ZONE_GAZA)); + } + + @Test(groups={"tck"}) + public void test_atZone_dstOverlap() { + LocalDateTime t = LocalDateTime.of(2007, 10, 28, 2, 30); + assertEquals(t.atZone(ZONE_PARIS), + ZonedDateTime.ofStrict(LocalDateTime.of(2007, 10, 28, 2, 30), OFFSET_PTWO, ZONE_PARIS)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atZone_nullTimeZone() { + LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30); + t.atZone((ZoneId) null); + } + + //----------------------------------------------------------------------- + // toEpochSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toEpochSecond_afterEpoch() { + for (int i = -5; i < 5; i++) { + ZoneOffset offset = ZoneOffset.ofHours(i); + for (int j = 0; j < 100000; j++) { + LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).plusSeconds(j); + assertEquals(a.toEpochSecond(offset), j - i * 3600); + } + } + } + + @Test(groups={"tck"}) + public void test_toEpochSecond_beforeEpoch() { + for (int i = 0; i < 100000; i++) { + LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).minusSeconds(i); + assertEquals(a.toEpochSecond(ZoneOffset.UTC), -i); + } + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + test_comparisons_LocalDateTime( + LocalDate.of(Year.MIN_VALUE, 1, 1), + LocalDate.of(Year.MIN_VALUE, 12, 31), + LocalDate.of(-1, 1, 1), + LocalDate.of(-1, 12, 31), + LocalDate.of(0, 1, 1), + LocalDate.of(0, 12, 31), + LocalDate.of(1, 1, 1), + LocalDate.of(1, 12, 31), + LocalDate.of(2008, 1, 1), + LocalDate.of(2008, 2, 29), + LocalDate.of(2008, 12, 31), + LocalDate.of(Year.MAX_VALUE, 1, 1), + LocalDate.of(Year.MAX_VALUE, 12, 31) + ); + } + + void test_comparisons_LocalDateTime(LocalDate... localDates) { + test_comparisons_LocalDateTime( + localDates, + LocalTime.MIDNIGHT, + LocalTime.of(0, 0, 0, 999999999), + LocalTime.of(0, 0, 59, 0), + LocalTime.of(0, 0, 59, 999999999), + LocalTime.of(0, 59, 0, 0), + LocalTime.of(0, 59, 59, 999999999), + LocalTime.NOON, + LocalTime.of(12, 0, 0, 999999999), + LocalTime.of(12, 0, 59, 0), + LocalTime.of(12, 0, 59, 999999999), + LocalTime.of(12, 59, 0, 0), + LocalTime.of(12, 59, 59, 999999999), + LocalTime.of(23, 0, 0, 0), + LocalTime.of(23, 0, 0, 999999999), + LocalTime.of(23, 0, 59, 0), + LocalTime.of(23, 0, 59, 999999999), + LocalTime.of(23, 59, 0, 0), + LocalTime.of(23, 59, 59, 999999999) + ); + } + + void test_comparisons_LocalDateTime(LocalDate[] localDates, LocalTime... localTimes) { + LocalDateTime[] localDateTimes = new LocalDateTime[localDates.length * localTimes.length]; + int i = 0; + + for (LocalDate localDate : localDates) { + for (LocalTime localTime : localTimes) { + localDateTimes[i++] = LocalDateTime.of(localDate, localTime); + } + } + + doTest_comparisons_LocalDateTime(localDateTimes); + } + + void doTest_comparisons_LocalDateTime(LocalDateTime[] localDateTimes) { + for (int i = 0; i < localDateTimes.length; i++) { + LocalDateTime a = localDateTimes[i]; + for (int j = 0; j < localDateTimes.length; j++) { + LocalDateTime b = localDateTimes[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + TEST_2007_07_15_12_30_40_987654321.compareTo(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isBefore_ObjectNull() { + TEST_2007_07_15_12_30_40_987654321.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isAfter_ObjectNull() { + TEST_2007_07_15_12_30_40_987654321.isAfter(null); + } + + @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonLocalDateTime() { + Comparable c = TEST_2007_07_15_12_30_40_987654321; + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @DataProvider(name="sampleDateTimes") + Iterator provider_sampleDateTimes() { + return new Iterator() { + Object[][] sampleDates = provider_sampleDates(); + Object[][] sampleTimes = provider_sampleTimes(); + int datesIndex = 0; + int timesIndex = 0; + + public boolean hasNext() { + return datesIndex < sampleDates.length; + } + + public Object[] next() { + Object[] sampleDate = sampleDates[datesIndex]; + Object[] sampleTime = sampleTimes[timesIndex]; + + Object[] ret = new Object[sampleDate.length + sampleTime.length]; + + System.arraycopy(sampleDate, 0, ret, 0, sampleDate.length); + System.arraycopy(sampleTime, 0, ret, sampleDate.length, sampleTime.length); + + if (++timesIndex == sampleTimes.length) { + datesIndex++; + timesIndex = 0; + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_true(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n); + assertTrue(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_year_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y + 1, m, d, h, mi, s, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_month_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m + 1, d, h, mi, s, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_day_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d + 1, h, mi, s, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_hour_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d, h + 1, mi, s, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_minute_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d, h, mi + 1, s, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_second_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s + 1, n); + assertFalse(a.equals(b)); + } + + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_equals_false_nano_differs(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n + 1); + assertFalse(a.equals(b)); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.equals(TEST_2007_07_15_12_30_40_987654321), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.equals("2007-07-15T12:30:40.987654321"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDateTimes", groups={"tck"}) + public void test_hashCode(int y, int m, int d, int h, int mi, int s, int n) { + LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n); + assertEquals(a.hashCode(), a.hashCode()); + LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n); + assertEquals(a.hashCode(), b.hashCode()); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {2008, 7, 5, 2, 1, 0, 0, "2008-07-05T02:01"}, + {2007, 12, 31, 23, 59, 1, 0, "2007-12-31T23:59:01"}, + {999, 12, 31, 23, 59, 59, 990000000, "0999-12-31T23:59:59.990"}, + {-1, 1, 2, 23, 59, 59, 999990000, "-0001-01-02T23:59:59.999990"}, + {-2008, 1, 2, 23, 59, 59, 999999990, "-2008-01-02T23:59:59.999999990"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int y, int m, int d, int h, int mi, int s, int n, String expected) { + LocalDateTime t = LocalDateTime.of(y, m, d, h, mi, s, n); + String str = t.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + LocalDateTime.of(2010, 12, 3, 11, 30, 45).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKLocalTime.java b/jdk/test/java/time/tck/java/time/TCKLocalTime.java new file mode 100644 index 00000000000..1cc5486c7e2 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java @@ -0,0 +1,2226 @@ +/* + * 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) 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; + +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +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.assertNotNull; +import static org.testng.Assert.assertTrue; +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.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. + */ +@Test +public class TCKLocalTime extends AbstractDateTimeTest { + + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + + private LocalTime TEST_12_30_40_987654321; + + private static final TemporalUnit[] INVALID_UNITS; + static { + EnumSet set = EnumSet.range(WEEKS, FOREVER); + INVALID_UNITS = (TemporalUnit[]) set.toArray(new TemporalUnit[set.size()]); + } + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_12_30_40_987654321 = LocalTime.of(12, 30, 40, 987654321); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_12_30_40_987654321, LocalTime.MIN, LocalTime.MAX, LocalTime.MIDNIGHT, LocalTime.NOON}; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + NANO_OF_DAY, + MICRO_OF_SECOND, + MICRO_OF_DAY, + MILLI_OF_SECOND, + MILLI_OF_DAY, + SECOND_OF_MINUTE, + SECOND_OF_DAY, + MINUTE_OF_HOUR, + MINUTE_OF_DAY, + CLOCK_HOUR_OF_AMPM, + HOUR_OF_AMPM, + CLOCK_HOUR_OF_DAY, + HOUR_OF_DAY, + AMPM_OF_DAY, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_12_30_40_987654321); + assertSerializable(LocalTime.MIN); + assertSerializable(LocalTime.MAX); + } + + @Test + public void test_serialization_format_h() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(-1 - 22); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 0), bytes); + } + + @Test + public void test_serialization_format_hm() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(-1 - 17); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17), bytes); + } + + @Test + public void test_serialization_format_hms() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(-1 - 59); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17, 59), bytes); + } + + @Test + public void test_serialization_format_hmsn() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(459_000_000); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17, 59, 459_000_000), bytes); + } + + //----------------------------------------------------------------------- + private void check(LocalTime test, int h, int m, int s, int n) { + assertEquals(test.getHour(), h); + assertEquals(test.getMinute(), m); + assertEquals(test.getSecond(), s); + assertEquals(test.getNano(), n); + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + assertEquals(LocalTime.of(h, m, s, n), test); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test(groups={"tck","implementation"}) + public void constant_MIDNIGHT() { + check(LocalTime.MIDNIGHT, 0, 0, 0, 0); + } + + @Test + public void constant_MIDDAY() { + check(LocalTime.NOON, 12, 0, 0, 0); + } + + @Test + public void constant_MIN() { + check(LocalTime.MIN, 0, 0, 0, 0); + } + + @Test + public void constant_MAX() { + check(LocalTime.MAX, 23, 59, 59, 999999999); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + LocalTime expected = LocalTime.now(Clock.systemDefaultZone()); + LocalTime test = LocalTime.now(); + long diff = Math.abs(test.toNanoOfDay() - expected.toNanoOfDay()); + assertTrue(diff < 100000000); // less than 0.1 secs + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + LocalTime.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + LocalTime expected = LocalTime.now(Clock.system(zone)); + LocalTime test = LocalTime.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = LocalTime.now(Clock.system(zone)); + test = LocalTime.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + LocalTime.now((Clock) null); + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i, 8); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + LocalTime test = LocalTime.now(clock); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 8); + } + } + + @Test(groups={"tck"}) + public void now_Clock_beforeEpoch() { + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i, 8); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + LocalTime test = LocalTime.now(clock); + assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24); + assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60); + assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60); + assertEquals(test.getNano(), 8); + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock_max() { + Clock clock = Clock.fixed(Instant.MAX, ZoneOffset.UTC); + LocalTime test = LocalTime.now(clock); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 999_999_999); + } + + @Test(groups={"tck"}) + public void now_Clock_min() { + Clock clock = Clock.fixed(Instant.MIN, ZoneOffset.UTC); + LocalTime test = LocalTime.now(clock); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + //----------------------------------------------------------------------- + // of() factories + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_time_2ints() { + LocalTime test = LocalTime.of(12, 30); + check(test, 12, 30, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_2ints_hourTooLow() { + LocalTime.of(-1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_2ints_hourTooHigh() { + LocalTime.of(24, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_2ints_minuteTooLow() { + LocalTime.of(0, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_2ints_minuteTooHigh() { + LocalTime.of(0, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_time_3ints() { + LocalTime test = LocalTime.of(12, 30, 40); + check(test, 12, 30, 40, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_hourTooLow() { + LocalTime.of(-1, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_hourTooHigh() { + LocalTime.of(24, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_minuteTooLow() { + LocalTime.of(0, -1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_minuteTooHigh() { + LocalTime.of(0, 60, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_secondTooLow() { + LocalTime.of(0, 0, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_3ints_secondTooHigh() { + LocalTime.of(0, 0, 60); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_time_4ints() { + LocalTime test = LocalTime.of(12, 30, 40, 987654321); + check(test, 12, 30, 40, 987654321); + test = LocalTime.of(12, 0, 40, 987654321); + check(test, 12, 0, 40, 987654321); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_hourTooLow() { + LocalTime.of(-1, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_hourTooHigh() { + LocalTime.of(24, 0, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_minuteTooLow() { + LocalTime.of(0, -1, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_minuteTooHigh() { + LocalTime.of(0, 60, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_secondTooLow() { + LocalTime.of(0, 0, -1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_secondTooHigh() { + LocalTime.of(0, 0, 60, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_nanoTooLow() { + LocalTime.of(0, 0, 0, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_time_4ints_nanoTooHigh() { + LocalTime.of(0, 0, 0, 1000000000); + } + + //----------------------------------------------------------------------- + // ofSecondOfDay(long) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofSecondOfDay() { + LocalTime localTime = LocalTime.ofSecondOfDay(2 * 60 * 60 + 17 * 60 + 23); + check(localTime, 2, 17, 23, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofSecondOfDay_tooLow() { + LocalTime.ofSecondOfDay(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofSecondOfDay_tooHigh() { + 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) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofNanoOfDay() { + LocalTime localTime = LocalTime.ofNanoOfDay(60 * 60 * 1000000000L + 17); + check(localTime, 1, 0, 0, 17); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofNanoOfDay_tooLow() { + LocalTime.ofNanoOfDay(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofNanoOfDay_tooHigh() { + LocalTime.ofNanoOfDay(24 * 60 * 60 * 1000000000L); + } + + //----------------------------------------------------------------------- + // from() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_from_TemporalAccessor() { + assertEquals(LocalTime.from(LocalTime.of(17, 30)), LocalTime.of(17, 30)); + assertEquals(LocalTime.from(LocalDateTime.of(2012, 5, 1, 17, 30)), LocalTime.of(17, 30)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_invalid_noDerive() { + LocalTime.from(LocalDate.of(2007, 7, 15)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_null() { + LocalTime.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider = "sampleToString", groups={"tck"}) + public void factory_parse_validText(int h, int m, int s, int n, String parsable) { + LocalTime t = LocalTime.parse(parsable); + assertNotNull(t, parsable); + assertEquals(t.getHour(), h); + assertEquals(t.getMinute(), m); + assertEquals(t.getSecond(), s); + assertEquals(t.getNano(), n); + } + + @DataProvider(name="sampleBadParse") + Object[][] provider_sampleBadParse() { + return new Object[][]{ + {"00;00"}, + {"12-00"}, + {"-01:00"}, + {"00:00:00-09"}, + {"00:00:00,09"}, + {"00:00:abs"}, + {"11"}, + {"11:30+01:00"}, + {"11:30+01:00[Europe/Paris]"}, + }; + } + + @Test(dataProvider = "sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_invalidText(String unparsable) { + LocalTime.parse(unparsable); + } + + //-----------------------------------------------------------------------s + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalHour() { + LocalTime.parse("25:00"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalMinute() { + LocalTime.parse("12:60"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalSecond() { + LocalTime.parse("12:12:60"); + } + + //-----------------------------------------------------------------------s + @Test(expectedExceptions = {NullPointerException.class}, groups={"tck"}) + public void factory_parse_nullTest() { + LocalTime.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + LocalTime.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + LocalTime.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + LocalTime test = TEST_12_30_40_987654321; + assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12); + assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321); + + assertEquals(test.get(ChronoField.SECOND_OF_DAY), 12 * 3600 + 30 * 60 + 40); + assertEquals(test.get(ChronoField.MINUTE_OF_DAY), 12 * 60 + 30); + assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.get(ChronoField.CLOCK_HOUR_OF_AMPM), 12); + assertEquals(test.get(ChronoField.CLOCK_HOUR_OF_DAY), 12); + assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1); + } + + @Test + public void test_getLong_TemporalField() { + LocalTime test = TEST_12_30_40_987654321; + assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12); + assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321); + + assertEquals(test.getLong(ChronoField.SECOND_OF_DAY), 12 * 3600 + 30 * 60 + 40); + assertEquals(test.getLong(ChronoField.MINUTE_OF_DAY), 12 * 60 + 30); + assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.getLong(ChronoField.CLOCK_HOUR_OF_AMPM), 12); + assertEquals(test.getLong(ChronoField.CLOCK_HOUR_OF_DAY), 12); + assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_12_30_40_987654321.query(null); + } + + //----------------------------------------------------------------------- + // get*() + //----------------------------------------------------------------------- + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {0, 0, 0, 0}, + {0, 0, 0, 1}, + {0, 0, 1, 0}, + {0, 0, 1, 1}, + {0, 1, 0, 0}, + {0, 1, 0, 1}, + {0, 1, 1, 0}, + {0, 1, 1, 1}, + {1, 0, 0, 0}, + {1, 0, 0, 1}, + {1, 0, 1, 0}, + {1, 0, 1, 1}, + {1, 1, 0, 0}, + {1, 1, 0, 1}, + {1, 1, 1, 0}, + {1, 1, 1, 1}, + }; + } + + //----------------------------------------------------------------------- + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_get(int h, int m, int s, int ns) { + LocalTime a = LocalTime.of(h, m, s, ns); + assertEquals(a.getHour(), h); + assertEquals(a.getMinute(), m); + assertEquals(a.getSecond(), s); + assertEquals(a.getNano(), ns); + } + + //----------------------------------------------------------------------- + // with() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_adjustment() { + final LocalTime sample = LocalTime.of(23, 5); + TemporalAdjuster adjuster = new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return sample; + } + }; + assertEquals(TEST_12_30_40_987654321.with(adjuster), sample); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_adjustment_null() { + TEST_12_30_40_987654321.with((TemporalAdjuster) null); + } + + //----------------------------------------------------------------------- + // withHour() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withHour_normal() { + LocalTime t = TEST_12_30_40_987654321; + for (int i = 0; i < 24; i++) { + t = t.withHour(i); + assertEquals(t.getHour(), i); + } + } + + @Test(groups={"tck"}) + public void test_withHour_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.withHour(12); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_withHour_toMidnight_equal() { + LocalTime t = LocalTime.of(1, 0).withHour(0); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_withHour_toMidday_equal() { + LocalTime t = LocalTime.of(1, 0).withHour(12); + assertEquals(t, LocalTime.NOON); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withHour_hourTooLow() { + TEST_12_30_40_987654321.withHour(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withHour_hourTooHigh() { + TEST_12_30_40_987654321.withHour(24); + } + + //----------------------------------------------------------------------- + // withMinute() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMinute_normal() { + LocalTime t = TEST_12_30_40_987654321; + for (int i = 0; i < 60; i++) { + t = t.withMinute(i); + assertEquals(t.getMinute(), i); + } + } + + @Test(groups={"tck"}) + public void test_withMinute_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.withMinute(30); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_withMinute_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 1).withMinute(0); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_withMinute_toMidday_equals() { + LocalTime t = LocalTime.of(12, 1).withMinute(0); + assertEquals(t, LocalTime.NOON); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMinute_minuteTooLow() { + TEST_12_30_40_987654321.withMinute(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMinute_minuteTooHigh() { + TEST_12_30_40_987654321.withMinute(60); + } + + //----------------------------------------------------------------------- + // withSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withSecond_normal() { + LocalTime t = TEST_12_30_40_987654321; + for (int i = 0; i < 60; i++) { + t = t.withSecond(i); + assertEquals(t.getSecond(), i); + } + } + + @Test(groups={"tck"}) + public void test_withSecond_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.withSecond(40); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_withSecond_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 0, 1).withSecond(0); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_withSecond_toMidday_equal() { + LocalTime t = LocalTime.of(12, 0, 1).withSecond(0); + assertEquals(t, LocalTime.NOON); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withSecond_secondTooLow() { + TEST_12_30_40_987654321.withSecond(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withSecond_secondTooHigh() { + TEST_12_30_40_987654321.withSecond(60); + } + + //----------------------------------------------------------------------- + // withNano() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withNanoOfSecond_normal() { + LocalTime t = TEST_12_30_40_987654321; + t = t.withNano(1); + assertEquals(t.getNano(), 1); + t = t.withNano(10); + assertEquals(t.getNano(), 10); + t = t.withNano(100); + assertEquals(t.getNano(), 100); + t = t.withNano(999999999); + assertEquals(t.getNano(), 999999999); + } + + @Test(groups={"tck"}) + public void test_withNanoOfSecond_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.withNano(987654321); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_withNanoOfSecond_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 0, 0, 1).withNano(0); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_withNanoOfSecond_toMidday_equal() { + LocalTime t = LocalTime.of(12, 0, 0, 1).withNano(0); + assertEquals(t, LocalTime.NOON); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withNanoOfSecond_nanoTooLow() { + TEST_12_30_40_987654321.withNano(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withNanoOfSecond_nanoTooHigh() { + TEST_12_30_40_987654321.withNano(1000000000); + } + + //----------------------------------------------------------------------- + // truncated(TemporalUnit) + //----------------------------------------------------------------------- + @DataProvider(name="truncatedToValid") + Object[][] data_truncatedToValid() { + return new Object[][] { + {LocalTime.of(1, 2, 3, 123_456_789), NANOS, LocalTime.of(1, 2, 3, 123_456_789)}, + {LocalTime.of(1, 2, 3, 123_456_789), MICROS, LocalTime.of(1, 2, 3, 123_456_000)}, + {LocalTime.of(1, 2, 3, 123_456_789), MILLIS, LocalTime.of(1, 2, 3, 1230_00_000)}, + {LocalTime.of(1, 2, 3, 123_456_789), SECONDS, LocalTime.of(1, 2, 3)}, + {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}, + }; + } + + @Test(groups={"tck"}, dataProvider="truncatedToValid") + public void test_truncatedTo_valid(LocalTime input, TemporalUnit unit, LocalTime expected) { + assertEquals(input.truncatedTo(unit), expected); + } + + @DataProvider(name="truncatedToInvalid") + Object[][] data_truncatedToInvalid() { + return new Object[][] { + {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}, + }; + } + + @Test(groups={"tck"}, dataProvider="truncatedToInvalid", expectedExceptions=DateTimeException.class) + public void test_truncatedTo_invalid(LocalTime input, TemporalUnit unit) { + input.truncatedTo(unit); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_12_30_40_987654321.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus(PlusAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plus_Adjuster_positiveHours() { + TemporalAdder 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); + 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; + 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); + 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_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); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_positiveHours() { + LocalTime t = TEST_12_30_40_987654321.plus(7, ChronoUnit.HOURS); + assertEquals(t, LocalTime.of(19, 30, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_negativeMinutes() { + LocalTime t = TEST_12_30_40_987654321.plus(-25, ChronoUnit.MINUTES); + assertEquals(t, LocalTime.of(12, 5, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_zero() { + LocalTime t = TEST_12_30_40_987654321.plus(0, ChronoUnit.MINUTES); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_invalidUnit() { + for (TemporalUnit unit : INVALID_UNITS) { + try { + TEST_12_30_40_987654321.plus(1, unit); + fail("Unit should not be allowed " + unit); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(groups={"tck"}) + public void test_plus_longTemporalUnit_multiples() { + assertEquals(TEST_12_30_40_987654321.plus(0, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.plus(1, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.plus(2, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.plus(-3, DAYS), TEST_12_30_40_987654321); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_longTemporalUnit_null() { + 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() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusHours_one() { + LocalTime t = LocalTime.MIDNIGHT; + for (int i = 0; i < 50; i++) { + t = t.plusHours(1); + assertEquals(t.getHour(), (i + 1) % 24); + } + } + + @Test(groups={"tck"}) + public void test_plusHours_fromZero() { + LocalTime base = LocalTime.MIDNIGHT; + for (int i = -50; i < 50; i++) { + LocalTime t = base.plusHours(i); + assertEquals(t.getHour(), (i + 72) % 24); + } + } + + @Test(groups={"tck"}) + public void test_plusHours_fromOne() { + LocalTime base = LocalTime.of(1, 0); + for (int i = -50; i < 50; i++) { + LocalTime t = base.plusHours(i); + assertEquals(t.getHour(), (1 + i + 72) % 24); + } + } + + @Test(groups={"tck"}) + public void test_plusHours_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.plusHours(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusHours_toMidnight_equal() { + LocalTime t = LocalTime.of(23, 0).plusHours(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_plusHours_toMidday_equal() { + LocalTime t = LocalTime.of(11, 0).plusHours(1); + assertEquals(t, LocalTime.NOON); + } + + @Test(groups={"tck"}) + public void test_plusHours_big() { + LocalTime t = LocalTime.of(2, 30).plusHours(Long.MAX_VALUE); + int hours = (int) (Long.MAX_VALUE % 24L); + assertEquals(t, LocalTime.of(2, 30).plusHours(hours)); + } + + //----------------------------------------------------------------------- + // plusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMinutes_one() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + for (int i = 0; i < 70; i++) { + t = t.plusMinutes(1); + min++; + if (min == 60) { + hour++; + min = 0; + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @Test(groups={"tck"}) + public void test_plusMinutes_fromZero() { + LocalTime base = LocalTime.MIDNIGHT; + int hour; + int min; + for (int i = -70; i < 70; i++) { + LocalTime t = base.plusMinutes(i); + if (i < -60) { + hour = 22; + min = i + 120; + } else if (i < 0) { + hour = 23; + min = i + 60; + } else if (i >= 60) { + hour = 1; + min = i - 60; + } else { + hour = 0; + min = i; + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @Test(groups={"tck"}) + public void test_plusMinutes_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.plusMinutes(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.plusMinutes(24 * 60); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_toMidnight_equal() { + LocalTime t = LocalTime.of(23, 59).plusMinutes(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_toMidday_equal() { + LocalTime t = LocalTime.of(11, 59).plusMinutes(1); + assertEquals(t, LocalTime.NOON); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_big() { + LocalTime t = LocalTime.of(2, 30).plusMinutes(Long.MAX_VALUE); + int mins = (int) (Long.MAX_VALUE % (24L * 60L)); + assertEquals(t, LocalTime.of(2, 30).plusMinutes(mins)); + } + + //----------------------------------------------------------------------- + // plusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusSeconds_one() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + int sec = 0; + for (int i = 0; i < 3700; i++) { + t = t.plusSeconds(1); + sec++; + if (sec == 60) { + min++; + sec = 0; + } + if (min == 60) { + hour++; + min = 0; + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + } + } + + @DataProvider(name="plusSeconds_fromZero") + Iterator plusSeconds_fromZero() { + return new Iterator() { + int delta = 30; + int i = -3660; + int hour = 22; + int min = 59; + int sec = 0; + + public boolean hasNext() { + return i <= 3660; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, hour, min, sec}; + i += delta; + sec += delta; + + if (sec >= 60) { + min++; + sec -= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="plusSeconds_fromZero", groups={"tck"}) + public void test_plusSeconds_fromZero(int seconds, int hour, int min, int sec) { + LocalTime base = LocalTime.MIDNIGHT; + LocalTime t = base.plusSeconds(seconds); + + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.plusSeconds(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.plusSeconds(24 * 60 * 60); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_toMidnight_equal() { + LocalTime t = LocalTime.of(23, 59, 59).plusSeconds(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_toMidday_equal() { + LocalTime t = LocalTime.of(11, 59, 59).plusSeconds(1); + assertEquals(t, LocalTime.NOON); + } + + //----------------------------------------------------------------------- + // plusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusNanos_halfABillion() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + int sec = 0; + int nanos = 0; + for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) { + t = t.plusNanos(500000000); + nanos += 500000000; + if (nanos == 1000000000) { + sec++; + nanos = 0; + } + if (sec == 60) { + min++; + sec = 0; + } + if (min == 60) { + hour++; + min = 0; + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + assertEquals(t.getNano(), nanos); + } + } + + @DataProvider(name="plusNanos_fromZero") + Iterator plusNanos_fromZero() { + return new Iterator() { + long delta = 7500000000L; + long i = -3660 * 1000000000L; + int hour = 22; + int min = 59; + int sec = 0; + long nanos = 0; + + public boolean hasNext() { + return i <= 3660 * 1000000000L; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, hour, min, sec, (int)nanos}; + i += delta; + nanos += delta; + + if (nanos >= 1000000000L) { + sec += nanos / 1000000000L; + nanos %= 1000000000L; + + if (sec >= 60) { + min++; + sec %= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="plusNanos_fromZero", groups={"tck"}) + public void test_plusNanos_fromZero(long nanoseconds, int hour, int min, int sec, int nanos) { + LocalTime base = LocalTime.MIDNIGHT; + LocalTime t = base.plusNanos(nanoseconds); + + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + assertEquals(nanos, t.getNano()); + } + + @Test(groups={"tck"}) + public void test_plusNanos_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.plusNanos(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusNanos_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_plusNanos_toMidnight_equal() { + LocalTime t = LocalTime.of(23, 59, 59, 999999999).plusNanos(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_plusNanos_toMidday_equal() { + LocalTime t = LocalTime.of(11, 59, 59, 999999999).plusNanos(1); + assertEquals(t, LocalTime.NOON); + } + + //----------------------------------------------------------------------- + // minus(MinusAdjuster) + //----------------------------------------------------------------------- + @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); + 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); + 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); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minus_Adjuster_wrap() { + TemporalSubtractor p = Period.ofTime(1, 0, 0); + 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_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); + } + + //----------------------------------------------------------------------- + // minus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_positiveHours() { + LocalTime t = TEST_12_30_40_987654321.minus(7, ChronoUnit.HOURS); + assertEquals(t, LocalTime.of(5, 30, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_negativeMinutes() { + LocalTime t = TEST_12_30_40_987654321.minus(-25, ChronoUnit.MINUTES); + assertEquals(t, LocalTime.of(12, 55, 40, 987654321)); + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_zero() { + LocalTime t = TEST_12_30_40_987654321.minus(0, ChronoUnit.MINUTES); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_invalidUnit() { + for (TemporalUnit unit : INVALID_UNITS) { + try { + TEST_12_30_40_987654321.minus(1, unit); + fail("Unit should not be allowed " + unit); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(groups={"tck"}) + public void test_minus_longTemporalUnit_long_multiples() { + assertEquals(TEST_12_30_40_987654321.minus(0, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.minus(1, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.minus(2, DAYS), TEST_12_30_40_987654321); + assertEquals(TEST_12_30_40_987654321.minus(-3, DAYS), TEST_12_30_40_987654321); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_longTemporalUnit_null() { + TEST_12_30_40_987654321.minus(1, (TemporalUnit) null); + } + + //----------------------------------------------------------------------- + // minusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusHours_one() { + LocalTime t = LocalTime.MIDNIGHT; + for (int i = 0; i < 50; i++) { + t = t.minusHours(1); + assertEquals(t.getHour(), (((-i + 23) % 24) + 24) % 24, String.valueOf(i)); + } + } + + @Test(groups={"tck"}) + public void test_minusHours_fromZero() { + LocalTime base = LocalTime.MIDNIGHT; + for (int i = -50; i < 50; i++) { + LocalTime t = base.minusHours(i); + assertEquals(t.getHour(), ((-i % 24) + 24) % 24); + } + } + + @Test(groups={"tck"}) + public void test_minusHours_fromOne() { + LocalTime base = LocalTime.of(1, 0); + for (int i = -50; i < 50; i++) { + LocalTime t = base.minusHours(i); + assertEquals(t.getHour(), (1 + (-i % 24) + 24) % 24); + } + } + + @Test(groups={"tck"}) + public void test_minusHours_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.minusHours(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusHours_toMidnight_equal() { + LocalTime t = LocalTime.of(1, 0).minusHours(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_minusHours_toMidday_equal() { + LocalTime t = LocalTime.of(13, 0).minusHours(1); + assertEquals(t, LocalTime.NOON); + } + + @Test(groups={"tck"}) + public void test_minusHours_big() { + LocalTime t = LocalTime.of(2, 30).minusHours(Long.MAX_VALUE); + int hours = (int) (Long.MAX_VALUE % 24L); + assertEquals(t, LocalTime.of(2, 30).minusHours(hours)); + } + + //----------------------------------------------------------------------- + // minusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMinutes_one() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + for (int i = 0; i < 70; i++) { + t = t.minusMinutes(1); + min--; + if (min == -1) { + hour--; + min = 59; + + if (hour == -1) { + hour = 23; + } + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @Test(groups={"tck"}) + public void test_minusMinutes_fromZero() { + LocalTime base = LocalTime.MIDNIGHT; + int hour = 22; + int min = 49; + for (int i = 70; i > -70; i--) { + LocalTime t = base.minusMinutes(i); + min++; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + } + } + + @Test(groups={"tck"}) + public void test_minusMinutes_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.minusMinutes(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.minusMinutes(24 * 60); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 1).minusMinutes(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_toMidday_equals() { + LocalTime t = LocalTime.of(12, 1).minusMinutes(1); + assertEquals(t, LocalTime.NOON); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_big() { + LocalTime t = LocalTime.of(2, 30).minusMinutes(Long.MAX_VALUE); + int mins = (int) (Long.MAX_VALUE % (24L * 60L)); + assertEquals(t, LocalTime.of(2, 30).minusMinutes(mins)); + } + + //----------------------------------------------------------------------- + // minusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusSeconds_one() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + int sec = 0; + for (int i = 0; i < 3700; i++) { + t = t.minusSeconds(1); + sec--; + if (sec == -1) { + min--; + sec = 59; + + if (min == -1) { + hour--; + min = 59; + + if (hour == -1) { + hour = 23; + } + } + } + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + } + } + + @DataProvider(name="minusSeconds_fromZero") + Iterator minusSeconds_fromZero() { + return new Iterator() { + int delta = 30; + int i = 3660; + int hour = 22; + int min = 59; + int sec = 0; + + public boolean hasNext() { + return i >= -3660; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, hour, min, sec}; + i -= delta; + sec += delta; + + if (sec >= 60) { + min++; + sec -= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="minusSeconds_fromZero", groups={"tck"}) + public void test_minusSeconds_fromZero(int seconds, int hour, int min, int sec) { + LocalTime base = LocalTime.MIDNIGHT; + LocalTime t = base.minusSeconds(seconds); + + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.minusSeconds(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.minusSeconds(24 * 60 * 60); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 0, 1).minusSeconds(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_toMidday_equal() { + LocalTime t = LocalTime.of(12, 0, 1).minusSeconds(1); + assertEquals(t, LocalTime.NOON); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_big() { + LocalTime t = LocalTime.of(2, 30).minusSeconds(Long.MAX_VALUE); + int secs = (int) (Long.MAX_VALUE % (24L * 60L * 60L)); + assertEquals(t, LocalTime.of(2, 30).minusSeconds(secs)); + } + + //----------------------------------------------------------------------- + // minusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusNanos_halfABillion() { + LocalTime t = LocalTime.MIDNIGHT; + int hour = 0; + int min = 0; + int sec = 0; + int nanos = 0; + for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) { + t = t.minusNanos(500000000); + nanos -= 500000000; + + if (nanos < 0) { + sec--; + nanos += 1000000000; + + if (sec == -1) { + min--; + sec += 60; + + if (min == -1) { + hour--; + min += 60; + + if (hour == -1) { + hour += 24; + } + } + } + } + + assertEquals(t.getHour(), hour); + assertEquals(t.getMinute(), min); + assertEquals(t.getSecond(), sec); + assertEquals(t.getNano(), nanos); + } + } + + @DataProvider(name="minusNanos_fromZero") + Iterator minusNanos_fromZero() { + return new Iterator() { + long delta = 7500000000L; + long i = 3660 * 1000000000L; + int hour = 22; + int min = 59; + int sec = 0; + long nanos = 0; + + public boolean hasNext() { + return i >= -3660 * 1000000000L; + } + + public Object[] next() { + final Object[] ret = new Object[] {i, hour, min, sec, (int)nanos}; + i -= delta; + nanos += delta; + + if (nanos >= 1000000000L) { + sec += nanos / 1000000000L; + nanos %= 1000000000L; + + if (sec >= 60) { + min++; + sec %= 60; + + if (min == 60) { + hour++; + min = 0; + + if (hour == 24) { + hour = 0; + } + } + } + } + + return ret; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="minusNanos_fromZero", groups={"tck"}) + public void test_minusNanos_fromZero(long nanoseconds, int hour, int min, int sec, int nanos) { + LocalTime base = LocalTime.MIDNIGHT; + LocalTime t = base.minusNanos(nanoseconds); + + assertEquals(hour, t.getHour()); + assertEquals(min, t.getMinute()); + assertEquals(sec, t.getSecond()); + assertEquals(nanos, t.getNano()); + } + + @Test(groups={"tck"}) + public void test_minusNanos_noChange_equal() { + LocalTime t = TEST_12_30_40_987654321.minusNanos(0); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusNanos_noChange_oneDay_equal() { + LocalTime t = TEST_12_30_40_987654321.minusNanos(24 * 60 * 60 * 1000000000L); + assertEquals(t, TEST_12_30_40_987654321); + } + + @Test(groups={"tck"}) + public void test_minusNanos_toMidnight_equal() { + LocalTime t = LocalTime.of(0, 0, 0, 1).minusNanos(1); + assertEquals(t, LocalTime.MIDNIGHT); + } + + @Test(groups={"tck"}) + public void test_minusNanos_toMidday_equal() { + LocalTime t = LocalTime.of(12, 0, 0, 1).minusNanos(1); + assertEquals(t, LocalTime.NOON); + } + + //----------------------------------------------------------------------- + // atDate() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atDate() { + LocalTime t = LocalTime.of(11, 30); + assertEquals(t.atDate(LocalDate.of(2012, 6, 30)), LocalDateTime.of(2012, 6, 30, 11, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atDate_nullDate() { + TEST_12_30_40_987654321.atDate((LocalDate) null); + } + + //----------------------------------------------------------------------- + // atOffset() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atOffset() { + LocalTime t = LocalTime.of(11, 30); + assertEquals(t.atOffset(OFFSET_PTWO), OffsetTime.of(LocalTime.of(11, 30), OFFSET_PTWO)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atOffset_nullZoneOffset() { + LocalTime t = LocalTime.of(11, 30); + t.atOffset((ZoneOffset) null); + } + + //----------------------------------------------------------------------- + // toSecondOfDay() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toSecondOfDay() { + LocalTime t = LocalTime.of(0, 0); + for (int i = 0; i < 24 * 60 * 60; i++) { + assertEquals(t.toSecondOfDay(), i); + t = t.plusSeconds(1); + } + } + + @Test(groups={"tck"}) + public void test_toSecondOfDay_fromNanoOfDay_symmetry() { + LocalTime t = LocalTime.of(0, 0); + for (int i = 0; i < 24 * 60 * 60; i++) { + assertEquals(LocalTime.ofSecondOfDay(t.toSecondOfDay()), t); + t = t.plusSeconds(1); + } + } + + //----------------------------------------------------------------------- + // toNanoOfDay() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toNanoOfDay() { + LocalTime t = LocalTime.of(0, 0); + for (int i = 0; i < 1000000; i++) { + assertEquals(t.toNanoOfDay(), i); + t = t.plusNanos(1); + } + t = LocalTime.of(0, 0); + for (int i = 1; i <= 1000000; i++) { + t = t.minusNanos(1); + assertEquals(t.toNanoOfDay(), 24 * 60 * 60 * 1000000000L - i); + } + } + + @Test(groups={"tck"}) + public void test_toNanoOfDay_fromNanoOfDay_symmetry() { + LocalTime t = LocalTime.of(0, 0); + for (int i = 0; i < 1000000; i++) { + assertEquals(LocalTime.ofNanoOfDay(t.toNanoOfDay()), t); + t = t.plusNanos(1); + } + t = LocalTime.of(0, 0); + for (int i = 1; i <= 1000000; i++) { + t = t.minusNanos(1); + assertEquals(LocalTime.ofNanoOfDay(t.toNanoOfDay()), t); + } + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + doTest_comparisons_LocalTime( + LocalTime.MIDNIGHT, + LocalTime.of(0, 0, 0, 999999999), + LocalTime.of(0, 0, 59, 0), + LocalTime.of(0, 0, 59, 999999999), + LocalTime.of(0, 59, 0, 0), + LocalTime.of(0, 59, 0, 999999999), + LocalTime.of(0, 59, 59, 0), + LocalTime.of(0, 59, 59, 999999999), + LocalTime.NOON, + LocalTime.of(12, 0, 0, 999999999), + LocalTime.of(12, 0, 59, 0), + LocalTime.of(12, 0, 59, 999999999), + LocalTime.of(12, 59, 0, 0), + LocalTime.of(12, 59, 0, 999999999), + LocalTime.of(12, 59, 59, 0), + LocalTime.of(12, 59, 59, 999999999), + LocalTime.of(23, 0, 0, 0), + LocalTime.of(23, 0, 0, 999999999), + LocalTime.of(23, 0, 59, 0), + LocalTime.of(23, 0, 59, 999999999), + LocalTime.of(23, 59, 0, 0), + LocalTime.of(23, 59, 0, 999999999), + LocalTime.of(23, 59, 59, 0), + LocalTime.of(23, 59, 59, 999999999) + ); + } + + void doTest_comparisons_LocalTime(LocalTime... localTimes) { + for (int i = 0; i < localTimes.length; i++) { + LocalTime a = localTimes[i]; + for (int j = 0; j < localTimes.length; j++) { + LocalTime b = localTimes[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + TEST_12_30_40_987654321.compareTo(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isBefore_ObjectNull() { + TEST_12_30_40_987654321.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isAfter_ObjectNull() { + TEST_12_30_40_987654321.isAfter(null); + } + + @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonLocalTime() { + Comparable c = TEST_12_30_40_987654321; + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_equals_true(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s, n); + assertEquals(a.equals(b), true); + } + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_equals_false_hour_differs(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h + 1, m, s, n); + 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) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m + 1, s, n); + 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) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s + 1, n); + 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) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s, n + 1); + assertEquals(a.equals(b), false); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_12_30_40_987654321.equals(TEST_12_30_40_987654321), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_12_30_40_987654321.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_12_30_40_987654321.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_hashCode_same(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s, n); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_hashCode_hour_differs(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h + 1, m, s, n); + assertEquals(a.hashCode() == b.hashCode(), false); + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_hashCode_minute_differs(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m + 1, s, n); + assertEquals(a.hashCode() == b.hashCode(), false); + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_hashCode_second_differs(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s + 1, n); + assertEquals(a.hashCode() == b.hashCode(), false); + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_hashCode_nano_differs(int h, int m, int s, int n) { + LocalTime a = LocalTime.of(h, m, s, n); + LocalTime b = LocalTime.of(h, m, s, n + 1); + assertEquals(a.hashCode() == b.hashCode(), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {0, 0, 0, 0, "00:00"}, + {1, 0, 0, 0, "01:00"}, + {23, 0, 0, 0, "23:00"}, + {0, 1, 0, 0, "00:01"}, + {12, 30, 0, 0, "12:30"}, + {23, 59, 0, 0, "23:59"}, + {0, 0, 1, 0, "00:00:01"}, + {0, 0, 59, 0, "00:00:59"}, + {0, 0, 0, 100000000, "00:00:00.100"}, + {0, 0, 0, 10000000, "00:00:00.010"}, + {0, 0, 0, 1000000, "00:00:00.001"}, + {0, 0, 0, 100000, "00:00:00.000100"}, + {0, 0, 0, 10000, "00:00:00.000010"}, + {0, 0, 0, 1000, "00:00:00.000001"}, + {0, 0, 0, 100, "00:00:00.000000100"}, + {0, 0, 0, 10, "00:00:00.000000010"}, + {0, 0, 0, 1, "00:00:00.000000001"}, + {0, 0, 0, 999999999, "00:00:00.999999999"}, + {0, 0, 0, 99999999, "00:00:00.099999999"}, + {0, 0, 0, 9999999, "00:00:00.009999999"}, + {0, 0, 0, 999999, "00:00:00.000999999"}, + {0, 0, 0, 99999, "00:00:00.000099999"}, + {0, 0, 0, 9999, "00:00:00.000009999"}, + {0, 0, 0, 999, "00:00:00.000000999"}, + {0, 0, 0, 99, "00:00:00.000000099"}, + {0, 0, 0, 9, "00:00:00.000000009"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int h, int m, int s, int n, String expected) { + LocalTime t = LocalTime.of(h, m, s, n); + String str = t.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("H m s"); + String t = LocalTime.of(11, 30, 45).toString(f); + assertEquals(t, "11 30 45"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + LocalTime.of(11, 30, 45).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKMonth.java b/jdk/test/java/time/tck/java/time/TCKMonth.java new file mode 100644 index 00000000000..6f6170d06f8 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKMonth.java @@ -0,0 +1,486 @@ +/* + * 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 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.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 org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Month. + */ +@Test +public class TCKMonth extends AbstractDateTimeTest { + + private static final int MAX_LENGTH = 12; + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {Month.JANUARY, Month.JUNE, Month.DECEMBER, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + MONTH_OF_YEAR, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_singleton() { + for (int i = 1; i <= MAX_LENGTH; i++) { + Month test = Month.of(i); + assertEquals(test.getValue(), i); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_tooLow() { + Month.of(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_tooHigh() { + Month.of(13); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(Month.from(LocalDate.of(2011, 6, 6)), Month.JUNE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + Month.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + Month.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(Month.JULY.get(ChronoField.MONTH_OF_YEAR), 7); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(Month.JULY.getLong(ChronoField.MONTH_OF_YEAR), 7); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query_chrono() { + assertEquals(Month.JUNE.query(Queries.chrono()), ISOChrono.INSTANCE); + assertEquals(Queries.chrono().queryFrom(Month.JUNE), ISOChrono.INSTANCE); + } + + @Test + public void test_query_zoneId() { + assertEquals(Month.JUNE.query(Queries.zoneId()), null); + assertEquals(Queries.zoneId().queryFrom(Month.JUNE), null); + } + + @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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + Month.JUNE.query(null); + } + + //----------------------------------------------------------------------- + // getText() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getText() { + assertEquals(Month.JANUARY.getText(TextStyle.SHORT, Locale.US), "Jan"); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void test_getText_nullStyle() { + Month.JANUARY.getText(null, Locale.US); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void test_getText_nullLocale() { + Month.JANUARY.getText(TextStyle.FULL, null); + } + + //----------------------------------------------------------------------- + // plus(long), plus(long,unit) + //----------------------------------------------------------------------- + @DataProvider(name="plus") + Object[][] data_plus() { + return new Object[][] { + {1, -13, 12}, + {1, -12, 1}, + {1, -11, 2}, + {1, -10, 3}, + {1, -9, 4}, + {1, -8, 5}, + {1, -7, 6}, + {1, -6, 7}, + {1, -5, 8}, + {1, -4, 9}, + {1, -3, 10}, + {1, -2, 11}, + {1, -1, 12}, + {1, 0, 1}, + {1, 1, 2}, + {1, 2, 3}, + {1, 3, 4}, + {1, 4, 5}, + {1, 5, 6}, + {1, 6, 7}, + {1, 7, 8}, + {1, 8, 9}, + {1, 9, 10}, + {1, 10, 11}, + {1, 11, 12}, + {1, 12, 1}, + {1, 13, 2}, + + {1, 1, 2}, + {2, 1, 3}, + {3, 1, 4}, + {4, 1, 5}, + {5, 1, 6}, + {6, 1, 7}, + {7, 1, 8}, + {8, 1, 9}, + {9, 1, 10}, + {10, 1, 11}, + {11, 1, 12}, + {12, 1, 1}, + + {1, -1, 12}, + {2, -1, 1}, + {3, -1, 2}, + {4, -1, 3}, + {5, -1, 4}, + {6, -1, 5}, + {7, -1, 6}, + {8, -1, 7}, + {9, -1, 8}, + {10, -1, 9}, + {11, -1, 10}, + {12, -1, 11}, + }; + } + + @Test(dataProvider="plus", groups={"tck"}) + public void test_plus_long(int base, long amount, int expected) { + assertEquals(Month.of(base).plus(amount), Month.of(expected)); + } + + //----------------------------------------------------------------------- + // minus(long), minus(long,unit) + //----------------------------------------------------------------------- + @DataProvider(name="minus") + Object[][] data_minus() { + return new Object[][] { + {1, -13, 2}, + {1, -12, 1}, + {1, -11, 12}, + {1, -10, 11}, + {1, -9, 10}, + {1, -8, 9}, + {1, -7, 8}, + {1, -6, 7}, + {1, -5, 6}, + {1, -4, 5}, + {1, -3, 4}, + {1, -2, 3}, + {1, -1, 2}, + {1, 0, 1}, + {1, 1, 12}, + {1, 2, 11}, + {1, 3, 10}, + {1, 4, 9}, + {1, 5, 8}, + {1, 6, 7}, + {1, 7, 6}, + {1, 8, 5}, + {1, 9, 4}, + {1, 10, 3}, + {1, 11, 2}, + {1, 12, 1}, + {1, 13, 12}, + }; + } + + @Test(dataProvider="minus", groups={"tck"}) + public void test_minus_long(int base, long amount, int expected) { + assertEquals(Month.of(base).minus(amount), Month.of(expected)); + } + + //----------------------------------------------------------------------- + // length(boolean) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_length_boolean_notLeapYear() { + assertEquals(Month.JANUARY.length(false), 31); + assertEquals(Month.FEBRUARY.length(false), 28); + assertEquals(Month.MARCH.length(false), 31); + assertEquals(Month.APRIL.length(false), 30); + assertEquals(Month.MAY.length(false), 31); + assertEquals(Month.JUNE.length(false), 30); + assertEquals(Month.JULY.length(false), 31); + assertEquals(Month.AUGUST.length(false), 31); + assertEquals(Month.SEPTEMBER.length(false), 30); + assertEquals(Month.OCTOBER.length(false), 31); + assertEquals(Month.NOVEMBER.length(false), 30); + assertEquals(Month.DECEMBER.length(false), 31); + } + + @Test(groups={"tck"}) + public void test_length_boolean_leapYear() { + assertEquals(Month.JANUARY.length(true), 31); + assertEquals(Month.FEBRUARY.length(true), 29); + assertEquals(Month.MARCH.length(true), 31); + assertEquals(Month.APRIL.length(true), 30); + assertEquals(Month.MAY.length(true), 31); + assertEquals(Month.JUNE.length(true), 30); + assertEquals(Month.JULY.length(true), 31); + assertEquals(Month.AUGUST.length(true), 31); + assertEquals(Month.SEPTEMBER.length(true), 30); + assertEquals(Month.OCTOBER.length(true), 31); + assertEquals(Month.NOVEMBER.length(true), 30); + assertEquals(Month.DECEMBER.length(true), 31); + } + + //----------------------------------------------------------------------- + // minLength() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minLength() { + assertEquals(Month.JANUARY.minLength(), 31); + assertEquals(Month.FEBRUARY.minLength(), 28); + assertEquals(Month.MARCH.minLength(), 31); + assertEquals(Month.APRIL.minLength(), 30); + assertEquals(Month.MAY.minLength(), 31); + assertEquals(Month.JUNE.minLength(), 30); + assertEquals(Month.JULY.minLength(), 31); + assertEquals(Month.AUGUST.minLength(), 31); + assertEquals(Month.SEPTEMBER.minLength(), 30); + assertEquals(Month.OCTOBER.minLength(), 31); + assertEquals(Month.NOVEMBER.minLength(), 30); + assertEquals(Month.DECEMBER.minLength(), 31); + } + + //----------------------------------------------------------------------- + // maxLength() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_maxLength() { + assertEquals(Month.JANUARY.maxLength(), 31); + assertEquals(Month.FEBRUARY.maxLength(), 29); + assertEquals(Month.MARCH.maxLength(), 31); + assertEquals(Month.APRIL.maxLength(), 30); + assertEquals(Month.MAY.maxLength(), 31); + assertEquals(Month.JUNE.maxLength(), 30); + assertEquals(Month.JULY.maxLength(), 31); + assertEquals(Month.AUGUST.maxLength(), 31); + assertEquals(Month.SEPTEMBER.maxLength(), 30); + assertEquals(Month.OCTOBER.maxLength(), 31); + assertEquals(Month.NOVEMBER.maxLength(), 30); + assertEquals(Month.DECEMBER.maxLength(), 31); + } + + //----------------------------------------------------------------------- + // firstDayOfYear(boolean) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_firstDayOfYear_notLeapYear() { + assertEquals(Month.JANUARY.firstDayOfYear(false), 1); + assertEquals(Month.FEBRUARY.firstDayOfYear(false), 1 + 31); + assertEquals(Month.MARCH.firstDayOfYear(false), 1 + 31 + 28); + assertEquals(Month.APRIL.firstDayOfYear(false), 1 + 31 + 28 + 31); + assertEquals(Month.MAY.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30); + assertEquals(Month.JUNE.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31); + assertEquals(Month.JULY.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30); + assertEquals(Month.AUGUST.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31); + assertEquals(Month.SEPTEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31); + assertEquals(Month.OCTOBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30); + assertEquals(Month.NOVEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31); + assertEquals(Month.DECEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30); + } + + @Test(groups={"tck"}) + public void test_firstDayOfYear_leapYear() { + assertEquals(Month.JANUARY.firstDayOfYear(true), 1); + assertEquals(Month.FEBRUARY.firstDayOfYear(true), 1 + 31); + assertEquals(Month.MARCH.firstDayOfYear(true), 1 + 31 + 29); + assertEquals(Month.APRIL.firstDayOfYear(true), 1 + 31 + 29 + 31); + assertEquals(Month.MAY.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30); + assertEquals(Month.JUNE.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31); + assertEquals(Month.JULY.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30); + assertEquals(Month.AUGUST.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31); + assertEquals(Month.SEPTEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31); + assertEquals(Month.OCTOBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30); + assertEquals(Month.NOVEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31); + assertEquals(Month.DECEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30); + } + + //----------------------------------------------------------------------- + // firstMonthOfQuarter() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_firstMonthOfQuarter() { + assertEquals(Month.JANUARY.firstMonthOfQuarter(), Month.JANUARY); + assertEquals(Month.FEBRUARY.firstMonthOfQuarter(), Month.JANUARY); + assertEquals(Month.MARCH.firstMonthOfQuarter(), Month.JANUARY); + assertEquals(Month.APRIL.firstMonthOfQuarter(), Month.APRIL); + assertEquals(Month.MAY.firstMonthOfQuarter(), Month.APRIL); + assertEquals(Month.JUNE.firstMonthOfQuarter(), Month.APRIL); + assertEquals(Month.JULY.firstMonthOfQuarter(), Month.JULY); + assertEquals(Month.AUGUST.firstMonthOfQuarter(), Month.JULY); + assertEquals(Month.SEPTEMBER.firstMonthOfQuarter(), Month.JULY); + assertEquals(Month.OCTOBER.firstMonthOfQuarter(), Month.OCTOBER); + assertEquals(Month.NOVEMBER.firstMonthOfQuarter(), Month.OCTOBER); + assertEquals(Month.DECEMBER.firstMonthOfQuarter(), Month.OCTOBER); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString() { + assertEquals(Month.JANUARY.toString(), "JANUARY"); + assertEquals(Month.FEBRUARY.toString(), "FEBRUARY"); + assertEquals(Month.MARCH.toString(), "MARCH"); + assertEquals(Month.APRIL.toString(), "APRIL"); + assertEquals(Month.MAY.toString(), "MAY"); + assertEquals(Month.JUNE.toString(), "JUNE"); + assertEquals(Month.JULY.toString(), "JULY"); + assertEquals(Month.AUGUST.toString(), "AUGUST"); + assertEquals(Month.SEPTEMBER.toString(), "SEPTEMBER"); + assertEquals(Month.OCTOBER.toString(), "OCTOBER"); + assertEquals(Month.NOVEMBER.toString(), "NOVEMBER"); + assertEquals(Month.DECEMBER.toString(), "DECEMBER"); + } + + //----------------------------------------------------------------------- + // generated methods + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_enum() { + assertEquals(Month.valueOf("JANUARY"), Month.JANUARY); + assertEquals(Month.values()[0], Month.JANUARY); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKZoneId.java b/jdk/test/java/time/tck/java/time/TCKZoneId.java new file mode 100644 index 00000000000..adc2bb6ee2f --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKZoneId.java @@ -0,0 +1,92 @@ +/* + * 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 java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; + +import java.time.ZoneId; + +import org.testng.annotations.Test; + +/** + * Test ZoneId. + */ +@Test +public class TCKZoneId extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(ZoneId.of("Europe/London")); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(7); + dos.writeUTF("Europe/London"); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneId.of("Europe/London"), bytes); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKZoneOffset.java b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java new file mode 100644 index 00000000000..4cfd40d9115 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java @@ -0,0 +1,680 @@ +/* + * 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 java.time.temporal.ChronoField.OFFSET_SECONDS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; +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; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +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 org.testng.annotations.Test; + +/** + * Test ZoneOffset. + */ +@Test +public class TCKZoneOffset extends AbstractDateTimeTest { + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {ZoneOffset.ofHours(1), ZoneOffset.ofHoursMinutesSeconds(-5, -6, -30) }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + OFFSET_SECONDS, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(ZoneOffset.of("+01:30")); + } + + @Test + public void test_serialization_format_quarterPositive() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(6); // stored as quarter hours + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofHoursMinutes(1, 30), bytes); + } + + @Test + public void test_serialization_format_quarterNegative() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(-10); // stored as quarter hours + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofHoursMinutes(-2, -30), bytes); + } + + @Test + public void test_serialization_format_full() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(127); + dos.writeInt(53265); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofTotalSeconds(53265), bytes); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void test_constant_UTC() { + ZoneOffset test = ZoneOffset.UTC; + doTestOffset(test, 0, 0, 0); + } + + @Test + public void test_constant_MIN() { + ZoneOffset test = ZoneOffset.MIN; + doTestOffset(test, -18, 0, 0); + } + + @Test + public void test_constant_MAX() { + ZoneOffset test = ZoneOffset.MAX; + doTestOffset(test, 18, 0, 0); + } + + //----------------------------------------------------------------------- + // of(String) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_string_UTC() { + String[] values = new String[] { + "Z", "+0", + "+00","+0000","+00:00","+000000","+00:00:00", + "-00","-0000","-00:00","-000000","-00:00:00", + }; + for (int i = 0; i < values.length; i++) { + ZoneOffset test = ZoneOffset.of(values[i]); + assertSame(test, ZoneOffset.UTC); + } + } + + @Test(groups={"tck"}) + public void test_factory_string_invalid() { + String[] values = new String[] { + "","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","ZZ", + "0", "+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", + "1", "+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", + }; + for (int i = 0; i < values.length; i++) { + try { + ZoneOffset.of(values[i]); + fail("Should have failed:" + values[i]); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_string_null() { + ZoneOffset.of((String) null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_string_singleDigitHours() { + for (int i = -9; i <= 9; i++) { + String str = (i < 0 ? "-" : "+") + Math.abs(i); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, 0, 0); + } + } + + @Test(groups={"tck"}) + public void test_factory_string_hours() { + for (int i = -18; i <= 18; i++) { + String str = (i < 0 ? "-" : "+") + Integer.toString(Math.abs(i) + 100).substring(1); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, 0, 0); + } + } + + @Test(groups={"tck"}) + public void test_factory_string_hours_minutes_noColon() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) { + String str = (i < 0 || j < 0 ? "-" : "+") + + Integer.toString(Math.abs(i) + 100).substring(1) + + Integer.toString(Math.abs(j) + 100).substring(1); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, j, 0); + } + } + } + ZoneOffset test1 = ZoneOffset.of("-1800"); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.of("+1800"); + doTestOffset(test2, 18, 0, 0); + } + + @Test(groups={"tck"}) + public void test_factory_string_hours_minutes_colon() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) { + String str = (i < 0 || j < 0 ? "-" : "+") + + Integer.toString(Math.abs(i) + 100).substring(1) + ":" + + Integer.toString(Math.abs(j) + 100).substring(1); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, j, 0); + } + } + } + ZoneOffset test1 = ZoneOffset.of("-18:00"); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.of("+18:00"); + doTestOffset(test2, 18, 0, 0); + } + + @Test(groups={"tck"}) + public void test_factory_string_hours_minutes_seconds_noColon() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + for (int k = -59; k <= 59; k++) { + if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) || + (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) { + String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") + + Integer.toString(Math.abs(i) + 100).substring(1) + + Integer.toString(Math.abs(j) + 100).substring(1) + + Integer.toString(Math.abs(k) + 100).substring(1); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, j, k); + } + } + } + } + ZoneOffset test1 = ZoneOffset.of("-180000"); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.of("+180000"); + doTestOffset(test2, 18, 0, 0); + } + + @Test(groups={"tck"}) + public void test_factory_string_hours_minutes_seconds_colon() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + for (int k = -59; k <= 59; k++) { + if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) || + (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) { + String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") + + Integer.toString(Math.abs(i) + 100).substring(1) + ":" + + Integer.toString(Math.abs(j) + 100).substring(1) + ":" + + Integer.toString(Math.abs(k) + 100).substring(1); + ZoneOffset test = ZoneOffset.of(str); + doTestOffset(test, i, j, k); + } + } + } + } + ZoneOffset test1 = ZoneOffset.of("-18:00:00"); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.of("+18:00:00"); + doTestOffset(test2, 18, 0, 0); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_hours() { + for (int i = -18; i <= 18; i++) { + ZoneOffset test = ZoneOffset.ofHours(i); + doTestOffset(test, i, 0, 0); + } + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_tooBig() { + ZoneOffset.ofHours(19); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_tooSmall() { + ZoneOffset.ofHours(-19); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_hours_minutes() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) { + ZoneOffset test = ZoneOffset.ofHoursMinutes(i, j); + doTestOffset(test, i, j, 0); + } + } + } + ZoneOffset test1 = ZoneOffset.ofHoursMinutes(-18, 0); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.ofHoursMinutes(18, 0); + doTestOffset(test2, 18, 0, 0); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_minutes_tooBig() { + ZoneOffset.ofHoursMinutes(19, 0); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_minutes_tooSmall() { + ZoneOffset.ofHoursMinutes(-19, 0); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_hours_minutes_seconds() { + for (int i = -17; i <= 17; i++) { + for (int j = -59; j <= 59; j++) { + for (int k = -59; k <= 59; k++) { + if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) || + (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) { + ZoneOffset test = ZoneOffset.ofHoursMinutesSeconds(i, j, k); + doTestOffset(test, i, j, k); + } + } + } + } + ZoneOffset test1 = ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0); + doTestOffset(test1, -18, 0, 0); + ZoneOffset test2 = ZoneOffset.ofHoursMinutesSeconds(18, 0, 0); + doTestOffset(test2, 18, 0, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_plusHoursMinusMinutes() { + ZoneOffset.ofHoursMinutesSeconds(1, -1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_plusHoursMinusSeconds() { + ZoneOffset.ofHoursMinutesSeconds(1, 0, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_minusHoursPlusMinutes() { + ZoneOffset.ofHoursMinutesSeconds(-1, 1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_minusHoursPlusSeconds() { + ZoneOffset.ofHoursMinutesSeconds(-1, 0, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_zeroHoursMinusMinutesPlusSeconds() { + ZoneOffset.ofHoursMinutesSeconds(0, -1, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_zeroHoursPlusMinutesMinusSeconds() { + ZoneOffset.ofHoursMinutesSeconds(0, 1, -1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_minutesTooLarge() { + ZoneOffset.ofHoursMinutesSeconds(0, 60, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_minutesTooSmall() { + ZoneOffset.ofHoursMinutesSeconds(0, -60, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_secondsTooLarge() { + ZoneOffset.ofHoursMinutesSeconds(0, 0, 60); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_hours_minutes_seconds_secondsTooSmall() { + ZoneOffset.ofHoursMinutesSeconds(0, 0, 60); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_minutes_seconds_hoursTooBig() { + ZoneOffset.ofHoursMinutesSeconds(19, 0, 0); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_factory_int_hours_minutes_seconds_hoursTooSmall() { + ZoneOffset.ofHoursMinutesSeconds(-19, 0, 0); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_ofTotalSeconds() { + assertEquals(ZoneOffset.ofTotalSeconds(60 * 60 + 1), ZoneOffset.ofHoursMinutesSeconds(1, 0, 1)); + assertEquals(ZoneOffset.ofTotalSeconds(18 * 60 * 60), ZoneOffset.ofHours(18)); + assertEquals(ZoneOffset.ofTotalSeconds(-18 * 60 * 60), ZoneOffset.ofHours(-18)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ofTotalSeconds_tooLarge() { + ZoneOffset.ofTotalSeconds(18 * 60 * 60 + 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ofTotalSeconds_tooSmall() { + ZoneOffset.ofTotalSeconds(-18 * 60 * 60 - 1); + } + + //----------------------------------------------------------------------- + // from() + //----------------------------------------------------------------------- + @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)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + ZoneOffset.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + ZoneOffset.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // getTotalSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getTotalSeconds() { + ZoneOffset offset = ZoneOffset.ofTotalSeconds(60 * 60 + 1); + assertEquals(offset.getTotalSeconds(), 60 * 60 + 1); + } + + //----------------------------------------------------------------------- + // getId() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getId() { + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0); + assertEquals(offset.getId(), "+01:00"); + offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3); + assertEquals(offset.getId(), "+01:02:03"); + offset = ZoneOffset.UTC; + assertEquals(offset.getId(), "Z"); + } + + //----------------------------------------------------------------------- + // getRules() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getRules() { + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3); + assertEquals(offset.getRules().isFixedOffset(), true); + assertEquals(offset.getRules().getOffset((Instant) null), offset); + assertEquals(offset.getRules().getDaylightSavings((Instant) null), Duration.ZERO); + assertEquals(offset.getRules().getStandardOffset((Instant) null), offset); + assertEquals(offset.getRules().nextTransition((Instant) null), null); + assertEquals(offset.getRules().previousTransition((Instant) null), null); + + assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, offset), true); + assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, ZoneOffset.UTC), false); + assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, null), false); + assertEquals(offset.getRules().getOffset((LocalDateTime) null), offset); + assertEquals(offset.getRules().getValidOffsets((LocalDateTime) null), Arrays.asList(offset)); + assertEquals(offset.getRules().getTransition((LocalDateTime) null), null); + assertEquals(offset.getRules().getTransitions().size(), 0); + assertEquals(offset.getRules().getTransitionRules().size(), 0); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(ZoneOffset.UTC.get(OFFSET_SECONDS), 0); + assertEquals(ZoneOffset.ofHours(-2).get(OFFSET_SECONDS), -7200); + assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).get(OFFSET_SECONDS), 65); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(ZoneOffset.UTC.getLong(OFFSET_SECONDS), 0); + assertEquals(ZoneOffset.ofHours(-2).getLong(OFFSET_SECONDS), -7200); + assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).getLong(OFFSET_SECONDS), 65); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + ZoneOffset.ofHoursMinutes(1, 30).query(null); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_compareTo() { + ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3); + ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4); + assertTrue(offset1.compareTo(offset2) > 0); + assertTrue(offset2.compareTo(offset1) < 0); + assertTrue(offset1.compareTo(offset1) == 0); + assertTrue(offset2.compareTo(offset2) == 0); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3); + ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4); + ZoneOffset offset2b = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4); + assertEquals(offset1.equals(offset2), false); + assertEquals(offset2.equals(offset1), false); + + assertEquals(offset1.equals(offset1), true); + assertEquals(offset2.equals(offset2), true); + assertEquals(offset2.equals(offset2b), true); + + assertEquals(offset1.hashCode() == offset1.hashCode(), true); + assertEquals(offset2.hashCode() == offset2.hashCode(), true); + assertEquals(offset2.hashCode() == offset2b.hashCode(), true); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString() { + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0); + assertEquals(offset.toString(), "+01:00"); + offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3); + assertEquals(offset.toString(), "+01:02:03"); + offset = ZoneOffset.UTC; + assertEquals(offset.toString(), "Z"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + private void doTestOffset(ZoneOffset offset, int hours, int minutes, int seconds) { + assertEquals(offset.getTotalSeconds(), hours * 60 * 60 + minutes * 60 + seconds); + final String id; + if (hours == 0 && minutes == 0 && seconds == 0) { + id = "Z"; + } else { + String str = (hours < 0 || minutes < 0 || seconds < 0) ? "-" : "+"; + str += Integer.toString(Math.abs(hours) + 100).substring(1); + str += ":"; + str += Integer.toString(Math.abs(minutes) + 100).substring(1); + if (seconds != 0) { + str += ":"; + str += Integer.toString(Math.abs(seconds) + 100).substring(1); + } + id = str; + } + assertEquals(offset.getId(), id); + assertEquals(offset, ZoneOffset.ofHoursMinutesSeconds(hours, minutes, seconds)); + if (seconds == 0) { + assertEquals(offset, ZoneOffset.ofHoursMinutes(hours, minutes)); + if (minutes == 0) { + assertEquals(offset, ZoneOffset.ofHours(hours)); + } + } + assertEquals(ZoneOffset.of(id), offset); + assertEquals(offset.toString(), id); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java new file mode 100644 index 00000000000..df18b4f246f --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -0,0 +1,2166 @@ +/* + * 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 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; +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.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +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.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +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.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.testng.Assert.assertEquals; +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.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.TemporalAdjuster; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalField; +import java.time.temporal.ISOChrono; +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.DateTimeParseException; +import java.time.temporal.OffsetDateTime; +import java.time.temporal.Year; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ZonedDateTime. + */ +@Test +public class TCKZonedDateTime extends AbstractDateTimeTest { + + private static final ZoneOffset OFFSET_0100 = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_0130 = ZoneOffset.of("+01:30"); + private static final ZoneOffset OFFSET_MAX = ZoneOffset.MAX; + private static final ZoneOffset OFFSET_MIN = ZoneOffset.MIN; + + private static final ZoneId ZONE_0100 = OFFSET_0100; + private static final ZoneId ZONE_0200 = OFFSET_0200; + private static final ZoneId ZONE_M0100 = ZoneOffset.ofHours(-1); + private static final ZoneId ZONE_LONDON = ZoneId.of("Europe/London"); + private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); + private LocalDateTime TEST_PARIS_GAP_2008_03_30_02_30; + private LocalDateTime TEST_PARIS_OVERLAP_2008_10_26_02_30; + private LocalDateTime TEST_LOCAL_2008_06_30_11_30_59_500; + private ZonedDateTime TEST_DATE_TIME; + private ZonedDateTime TEST_DATE_TIME_PARIS; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_LOCAL_2008_06_30_11_30_59_500 = LocalDateTime.of(2008, 6, 30, 11, 30, 59, 500); + TEST_DATE_TIME = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + TEST_DATE_TIME_PARIS = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS); + TEST_PARIS_OVERLAP_2008_10_26_02_30 = LocalDateTime.of(2008, 10, 26, 2, 30); + TEST_PARIS_GAP_2008_03_30_02_30 = LocalDateTime.of(2008, 3, 30, 2, 30); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_DATE_TIME, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + NANO_OF_DAY, + MICRO_OF_SECOND, + MICRO_OF_DAY, + MILLI_OF_SECOND, + MILLI_OF_DAY, + SECOND_OF_MINUTE, + SECOND_OF_DAY, + MINUTE_OF_HOUR, + MINUTE_OF_DAY, + CLOCK_HOUR_OF_AMPM, + HOUR_OF_AMPM, + CLOCK_HOUR_OF_DAY, + HOUR_OF_DAY, + AMPM_OF_DAY, + 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, + INSTANT_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_DATE_TIME); + } + + @Test + public void test_serialization_format_zoneId() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(6); + dos.writeInt(2012); // date + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); // time + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(470_000_000); + dos.writeByte(4); // offset + dos.writeByte(7); // zoneId + dos.writeUTF("Europe/London"); + } + byte[] bytes = baos.toByteArray(); + ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneId.of("Europe/London")); + assertSerializedBySer(zdt, bytes); + } + + @Test + public void test_serialization_format_zoneOffset() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(6); + dos.writeInt(2012); // date + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); // time + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(470_000_000); + dos.writeByte(4); // offset + dos.writeByte(8); // zoneId + dos.writeByte(4); + } + byte[] bytes = baos.toByteArray(); + ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneOffset.ofHours(1)); + assertSerializedBySer(zdt, bytes); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + ZonedDateTime expected = ZonedDateTime.now(Clock.systemDefaultZone()); + ZonedDateTime test = ZonedDateTime.now(); + long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().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()); + } + assertTrue(diff < 100000000); // less than 0.1 secs + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + ZonedDateTime.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + ZonedDateTime expected = ZonedDateTime.now(Clock.system(zone)); + ZonedDateTime test = ZonedDateTime.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = ZonedDateTime.now(Clock.system(zone)); + test = ZonedDateTime.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + ZonedDateTime.now((Clock)null); + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_utc() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + ZonedDateTime test = ZonedDateTime.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2)); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 123456789); + assertEquals(test.getOffset(), ZoneOffset.UTC); + assertEquals(test.getZone(), ZoneOffset.UTC); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_zone() { + ZoneId zone = ZoneId.of("Europe/London"); + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + ZonedDateTime expected = ZonedDateTime.ofInstant(instant, zone); + Clock clock = Clock.fixed(expected.toInstant(), zone); + ZonedDateTime test = ZonedDateTime.now(clock); + assertEquals(test, expected); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_beforeEpoch() { + LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L); + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + ZonedDateTime test = ZonedDateTime.now(clock); + assertEquals(test.getYear(), 1969); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + expected = expected.minusSeconds(1); + assertEquals(test.getTime(), expected); + assertEquals(test.getOffset(), ZoneOffset.UTC); + assertEquals(test.getZone(), ZoneOffset.UTC); + } + } + + @Test(groups={"tck"}) + public void now_Clock_offsets() { + ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(1970, 1, 1, 12, 0), ZoneOffset.UTC); + for (int i = -9; i < 15; i++) { + ZoneOffset offset = ZoneOffset.ofHours(i); + Clock clock = Clock.fixed(base.toInstant(), offset); + ZonedDateTime test = ZonedDateTime.now(clock); + assertEquals(test.getHour(), (12 + i) % 24); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + assertEquals(test.getOffset(), offset); + assertEquals(test.getZone(), offset); + } + } + + //----------------------------------------------------------------------- + // dateTime factories + //----------------------------------------------------------------------- + void check(ZonedDateTime test, int y, int m, int d, int h, int min, int s, int n, ZoneOffset offset, ZoneId zone) { + assertEquals(test.getYear(), y); + assertEquals(test.getMonth().getValue(), m); + assertEquals(test.getDayOfMonth(), d); + assertEquals(test.getHour(), h); + assertEquals(test.getMinute(), min); + assertEquals(test.getSecond(), s); + assertEquals(test.getNano(), n); + assertEquals(test.getOffset(), offset); + assertEquals(test.getZone(), zone); + } + + //----------------------------------------------------------------------- + // 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); + ZonedDateTime test = ZonedDateTime.of(base, ZONE_PARIS); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateTime_nullDateTime() { + ZonedDateTime.of((LocalDateTime) null, ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateTime_nullZone() { + LocalDateTime base = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500); + ZonedDateTime.of(base, null); + } + + //----------------------------------------------------------------------- + // ofInstant(Instant, ZoneId) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofInstant_Instant_ZR() { + Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 35).toInstant(OFFSET_0200); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS); + check(test, 2008, 6, 30, 11, 30, 10, 35, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_Instant_ZO() { + Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 45).toInstant(OFFSET_0200); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_0200); + check(test, 2008, 6, 30, 11, 30, 10, 45, OFFSET_0200, OFFSET_0200); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_Instant_inGap() { + Instant instant = TEST_PARIS_GAP_2008_03_30_02_30.toInstant(OFFSET_0100); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, 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_ofInstant_Instant_inOverlap_earlier() { + Instant instant = TEST_PARIS_OVERLAP_2008_10_26_02_30.toInstant(OFFSET_0200); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS); + check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS); // same time and offset + } + + @Test(groups={"tck"}) + public void factory_ofInstant_Instant_inOverlap_later() { + Instant instant = TEST_PARIS_OVERLAP_2008_10_26_02_30.toInstant(OFFSET_0100); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS); + check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS); // same time and offset + } + + @Test(groups={"tck"}) + public void factory_ofInstant_Instant_invalidOffset() { + Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).toInstant(OFFSET_0130); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS); + check(test, 2008, 6, 30, 12, 0, 10, 500, OFFSET_0200, ZONE_PARIS); // corrected offset, thus altered time + } + + @Test(groups={"tck"}) + public void factory_ofInstant_allSecsInDay() { + for (int i = 0; i < (24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_0100); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + 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(groups={"tck"}) + public void factory_ofInstant_allDaysInCycle() { + // sanity check using different algorithm + ZonedDateTime expected = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0).atZone(ZoneOffset.UTC); + for (long i = 0; i < 146097; i++) { + Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC); + assertEquals(test, expected); + expected = expected.plusDays(1); + } + } + + @Test(groups={"tck"}) + public void factory_ofInstant_minWithMinOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MIN.getTotalSeconds()); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MIN); + assertEquals(test.getYear(), Year.MIN_VALUE); + assertEquals(test.getMonth().getValue(), 1); + assertEquals(test.getDayOfMonth(), 1); + assertEquals(test.getOffset(), OFFSET_MIN); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_minWithMaxOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MAX.getTotalSeconds()); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MAX); + assertEquals(test.getYear(), Year.MIN_VALUE); + assertEquals(test.getMonth().getValue(), 1); + assertEquals(test.getDayOfMonth(), 1); + assertEquals(test.getOffset(), OFFSET_MAX); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_maxWithMinOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MAX_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MIN.getTotalSeconds()); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MIN); + assertEquals(test.getYear(), Year.MAX_VALUE); + assertEquals(test.getMonth().getValue(), 12); + assertEquals(test.getDayOfMonth(), 31); + assertEquals(test.getOffset(), OFFSET_MIN); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 0); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_maxWithMaxOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MAX_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MAX.getTotalSeconds()); + ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MAX); + assertEquals(test.getYear(), Year.MAX_VALUE); + assertEquals(test.getMonth().getValue(), 12); + assertEquals(test.getDayOfMonth(), 31); + assertEquals(test.getOffset(), OFFSET_MAX); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 0); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_maxInstantWithMaxOffset() { + Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE); + ZonedDateTime.ofInstant(instant, OFFSET_MAX); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_maxInstantWithMinOffset() { + Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE); + ZonedDateTime.ofInstant(instant, OFFSET_MIN); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_tooBig() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + long year = Year.MAX_VALUE + 1L; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L); + ZonedDateTime.ofInstant(instant, ZoneOffset.UTC); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofInstant_tooLow() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE - 1; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L); + ZonedDateTime.ofInstant(instant, ZoneOffset.UTC); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_Instant_nullInstant() { + ZonedDateTime.ofInstant((Instant) null, ZONE_0100); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_Instant_nullZone() { + ZonedDateTime.ofInstant(Instant.EPOCH, null); + } + + //----------------------------------------------------------------------- + // ofStrict(LocalDateTime, ZoneId, ZoneOffset) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO() { + LocalDateTime normal = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500); + ZonedDateTime test = ZonedDateTime.ofStrict(normal, OFFSET_0200, ZONE_PARIS); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_inGap() { + try { + ZonedDateTime.ofStrict(TEST_PARIS_GAP_2008_03_30_02_30, OFFSET_0100, ZONE_PARIS); + } catch (DateTimeException ex) { + assertEquals(ex.getMessage().contains(" gap"), true); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_inOverlap_invalidOfset() { + try { + ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0130, ZONE_PARIS); + } catch (DateTimeException ex) { + assertEquals(ex.getMessage().contains(" is not valid for "), true); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_invalidOffset() { + try { + ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0130, ZONE_PARIS); + } catch (DateTimeException ex) { + assertEquals(ex.getMessage().contains(" is not valid for "), true); + throw ex; + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_nullLDT() { + ZonedDateTime.ofStrict((LocalDateTime) null, OFFSET_0100, ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_nullZO() { + ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, null, ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofStrict_LDT_ZI_ZO_nullZI() { + ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0100, null); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_from_TemporalAccessor_ZDT() { + assertEquals(ZonedDateTime.from(TEST_DATE_TIME_PARIS), TEST_DATE_TIME_PARIS); + } + + @Test(groups={"tck"}) + public void factory_from_TemporalAccessor_LDT_ZoneId() { + assertEquals(ZonedDateTime.from(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return TEST_DATE_TIME_PARIS.getDateTime().isSupported(field); + } + @Override + public long getLong(TemporalField field) { + return TEST_DATE_TIME_PARIS.getDateTime().getLong(field); + } + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.zoneId()) { + return (R) TEST_DATE_TIME_PARIS.getZone(); + } + return TemporalAccessor.super.query(query); + } + }), TEST_DATE_TIME_PARIS); + } + + @Test(groups={"tck"}) + public void factory_from_TemporalAccessor_Instant_ZoneId() { + assertEquals(ZonedDateTime.from(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return field == INSTANT_SECONDS || field == NANO_OF_SECOND; + } + + @Override + public long getLong(TemporalField field) { + return TEST_DATE_TIME_PARIS.toInstant().getLong(field); + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.zoneId()) { + return (R) TEST_DATE_TIME_PARIS.getZone(); + } + return TemporalAccessor.super.query(query); + } + }), TEST_DATE_TIME_PARIS); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_invalid_noDerive() { + ZonedDateTime.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_null() { + ZonedDateTime.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleToString", groups={"tck"}) + 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); + 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]"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_invalidValue() { + ZonedDateTime.parse("2008-06-31T11:15+01:00[Europe/Paris]"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + ZonedDateTime.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s I"); + 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"); + ZonedDateTime.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + ZonedDateTime.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {2008, 6, 30, 11, 30, 20, 500, ZONE_0100}, + {2008, 6, 30, 11, 0, 0, 0, ZONE_0100}, + {2008, 6, 30, 11, 30, 20, 500, ZONE_PARIS}, + {2008, 6, 30, 11, 0, 0, 0, ZONE_PARIS}, + {2008, 6, 30, 23, 59, 59, 999999999, ZONE_0100}, + {-1, 1, 1, 0, 0, 0, 0, ZONE_0100}, + }; + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_get(int y, int o, int d, int h, int m, int s, int n, ZoneId zone) { + LocalDate localDate = LocalDate.of(y, o, d); + LocalTime localTime = LocalTime.of(h, m, s, n); + LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); + ZoneOffset offset = zone.getRules().getOffset(localDateTime); + ZonedDateTime a = ZonedDateTime.of(localDateTime, zone); + + 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()); + + assertEquals(a.getHour(), localTime.getHour()); + assertEquals(a.getMinute(), localTime.getMinute()); + assertEquals(a.getSecond(), localTime.getSecond()); + assertEquals(a.getNano(), localTime.getNano()); + + assertEquals(a.getDate(), localDate); + assertEquals(a.getTime(), localTime); + assertEquals(a.getDateTime(), localDateTime); + if (zone instanceof ZoneOffset) { + assertEquals(a.toString(), localDateTime.toString() + offset.toString()); + } else { + assertEquals(a.toString(), localDateTime.toString() + offset.toString() + "[" + zone.toString() + "]"); + } + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + ZonedDateTime test = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321), ZONE_0100); + 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.HOUR_OF_DAY), 12); + assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600); + } + + @Test + public void test_getLong_TemporalField() { + ZonedDateTime test = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321), ZONE_0100); + 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.HOUR_OF_DAY), 12); + assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600); + assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), test.toEpochSecond()); + } + + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @Test + public void test_query_chrono() { + assertEquals(TEST_DATE_TIME.query(Queries.chrono()), ISOChrono.INSTANCE); + assertEquals(Queries.chrono().queryFrom(TEST_DATE_TIME), ISOChrono.INSTANCE); + } + + @Test + public void test_query_zoneId() { + assertEquals(TEST_DATE_TIME.query(Queries.zoneId()), TEST_DATE_TIME.getZone()); + assertEquals(Queries.zoneId().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getZone()); + } + + @Test + public void test_query_precision() { + assertEquals(TEST_DATE_TIME.query(Queries.precision()), NANOS); + assertEquals(Queries.precision().queryFrom(TEST_DATE_TIME), NANOS); + } + + @Test + public void test_query_offset() { + assertEquals(TEST_DATE_TIME.query(Queries.offset()), TEST_DATE_TIME.getOffset()); + assertEquals(Queries.offset().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getOffset()); + } + + @Test + public void test_query_zone() { + assertEquals(TEST_DATE_TIME.query(Queries.zone()), TEST_DATE_TIME.getZone()); + assertEquals(Queries.zone().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getZone()); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_DATE_TIME.query(null); + } + + //----------------------------------------------------------------------- + // withEarlierOffsetAtOverlap() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withEarlierOffsetAtOverlap_notAtOverlap() { + ZonedDateTime base = ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0200, ZONE_PARIS); + ZonedDateTime test = base.withEarlierOffsetAtOverlap(); + assertEquals(test, base); // not changed + } + + @Test(groups={"tck"}) + public void test_withEarlierOffsetAtOverlap_atOverlap() { + 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 + } + + @Test(groups={"tck"}) + public void test_withEarlierOffsetAtOverlap_atOverlap_noChange() { + ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0200, ZONE_PARIS); + ZonedDateTime test = base.withEarlierOffsetAtOverlap(); + assertEquals(test, base); // not changed + } + + //----------------------------------------------------------------------- + // withLaterOffsetAtOverlap() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withLaterOffsetAtOverlap_notAtOverlap() { + ZonedDateTime base = ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0200, ZONE_PARIS); + ZonedDateTime test = base.withLaterOffsetAtOverlap(); + assertEquals(test, base); // not changed + } + + @Test(groups={"tck"}) + public void test_withLaterOffsetAtOverlap_atOverlap() { + 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 + } + + @Test(groups={"tck"}) + public void test_withLaterOffsetAtOverlap_atOverlap_noChange() { + ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0100, ZONE_PARIS); + ZonedDateTime test = base.withLaterOffsetAtOverlap(); + assertEquals(test, base); // not changed + } + + //----------------------------------------------------------------------- + // withZoneSameLocal(ZoneId) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withZoneSameLocal() { + 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()); + } + + @Test(groups={"implementation"}) + public void test_withZoneSameLocal_noChange() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.withZoneSameLocal(ZONE_0100); + assertEquals(test, base); + } + + @Test(groups={"tck"}) + public void test_withZoneSameLocal_retainOffset1() { + LocalDateTime ldt = LocalDateTime.of(2008, 11, 2, 1, 30, 59, 0); // overlap + ZonedDateTime base = ZonedDateTime.of(ldt, ZoneId.of("UTC-04:00") ); + ZonedDateTime test = base.withZoneSameLocal(ZoneId.of("America/New_York")); + assertEquals(base.getOffset(), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(), ZoneOffset.ofHours(-4)); + } + + @Test(groups={"tck"}) + public void test_withZoneSameLocal_retainOffset2() { + LocalDateTime ldt = LocalDateTime.of(2008, 11, 2, 1, 30, 59, 0); // overlap + ZonedDateTime base = ZonedDateTime.of(ldt, ZoneId.of("UTC-05:00") ); + ZonedDateTime test = base.withZoneSameLocal(ZoneId.of("America/New_York")); + assertEquals(base.getOffset(), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(), ZoneOffset.ofHours(-5)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_withZoneSameLocal_null() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + base.withZoneSameLocal(null); + } + + //----------------------------------------------------------------------- + // withZoneSameInstant() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withZoneSameInstant() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withZoneSameInstant(ZONE_0200); + ZonedDateTime expected = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.plusHours(1), ZONE_0200); + assertEquals(test, expected); + } + + @Test(groups={"tck"}) + public void test_withZoneSameInstant_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withZoneSameInstant(ZONE_0100); + assertEquals(test, base); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_withZoneSameInstant_null() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + base.withZoneSameInstant(null); + } + + //----------------------------------------------------------------------- + // withFixedOffsetZone() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withZoneLocked() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS); + ZonedDateTime test = base.withFixedOffsetZone(); + ZonedDateTime expected = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0200); + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalDateTime_sameOffset() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS); + ZonedDateTime test = base.with(LocalDateTime.of(2012, 7, 15, 14, 30)); + check(test, 2012, 7, 15, 14, 30, 0, 0, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalDateTime_adjustedOffset() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS); + ZonedDateTime test = base.with(LocalDateTime.of(2012, 1, 15, 14, 30)); + check(test, 2012, 1, 15, 14, 30, 0, 0, OFFSET_0100, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalDate() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS); + ZonedDateTime test = base.with(LocalDate.of(2012, 7, 28)); + check(test, 2012, 7, 28, 11, 30, 59, 500, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalTime() { + ZonedDateTime base = ZonedDateTime.of(TEST_PARIS_OVERLAP_2008_10_26_02_30, ZONE_PARIS); + ZonedDateTime test = base.with(LocalTime.of(2, 29)); + check(test, 2008, 10, 26, 2, 29, 0, 0, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_Year() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.with(Year.of(2007)); + assertEquals(test, ZonedDateTime.of(ldt.withYear(2007), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_Month_adjustedDayOfMonth() { + ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS); + ZonedDateTime test = base.with(Month.JUNE); + check(test, 2012, 6, 30, 0, 0, 0, 0, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_Offset_same() { + ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS); + ZonedDateTime test = base.with(ZoneOffset.ofHours(2)); + check(test, 2012, 7, 31, 0, 0, 0, 0, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_Offset_timeAdjust() { + ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS); + ZonedDateTime test = base.with(ZoneOffset.ofHours(1)); + check(test, 2012, 7, 31, 1, 0, 0, 0, OFFSET_0200, ZONE_PARIS); // time adjusted + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalDate_retainOffset1() { + ZoneId newYork = ZoneId.of("America/New_York"); + LocalDateTime ldt = LocalDateTime.of(2008, 11, 1, 1, 30); + ZonedDateTime base = ZonedDateTime.of(ldt, newYork); + assertEquals(base.getOffset(), ZoneOffset.ofHours(-4)); + ZonedDateTime test = base.with(LocalDate.of(2008, 11, 2)); + assertEquals(test.getOffset(), ZoneOffset.ofHours(-4)); + } + + @Test(groups={"tck"}) + public void test_with_WithAdjuster_LocalDate_retainOffset2() { + ZoneId newYork = ZoneId.of("America/New_York"); + LocalDateTime ldt = LocalDateTime.of(2008, 11, 3, 1, 30); + ZonedDateTime base = ZonedDateTime.of(ldt, newYork); + assertEquals(base.getOffset(), ZoneOffset.ofHours(-5)); + ZonedDateTime test = base.with(LocalDate.of(2008, 11, 2)); + assertEquals(test.getOffset(), ZoneOffset.ofHours(-5)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_WithAdjuster_null() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + base.with((TemporalAdjuster) null); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withYear(2007); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withYear(2007), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withYear_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withYear(2008); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // with(Month) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth_Month_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.with(JANUARY); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMonth(1), ZONE_0100)); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void test_withMonth_Month_null() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + base.with((Month) null); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withMonth(1); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMonth(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withMonth_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withMonth(6); + assertEquals(test, base); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooBig() { + TEST_DATE_TIME.withMonth(13); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooSmall() { + TEST_DATE_TIME.withMonth(0); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfMonth_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withDayOfMonth(15); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withDayOfMonth(15), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withDayOfMonth_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withDayOfMonth(30); + assertEquals(test, base); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_tooBig() { + LocalDateTime.of(2007, 7, 2, 11, 30).atZone(ZONE_PARIS).withDayOfMonth(32); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_tooSmall() { + TEST_DATE_TIME.withDayOfMonth(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_invalid31() { + LocalDateTime.of(2007, 6, 2, 11, 30).atZone(ZONE_PARIS).withDayOfMonth(31); + } + + //----------------------------------------------------------------------- + // withDayOfYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfYear_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withDayOfYear(33); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withDayOfYear(33), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withDayOfYear_noChange() { + LocalDateTime ldt = LocalDateTime.of(2008, 2, 5, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.withDayOfYear(36); + assertEquals(test, base); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_tooBig() { + TEST_DATE_TIME.withDayOfYear(367); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_tooSmall() { + TEST_DATE_TIME.withDayOfYear(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_invalid366() { + LocalDateTime.of(2007, 2, 2, 11, 30).atZone(ZONE_PARIS).withDayOfYear(366); + } + + //----------------------------------------------------------------------- + // withHour() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withHour_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withHour(15); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withHour(15), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withHour_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withHour(11); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withMinute() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMinute_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withMinute(15); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMinute(15), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withMinute_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withMinute(30); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withSecond_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withSecond(12); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withSecond(12), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withSecond_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withSecond(59); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withNano() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withNanoOfSecond_normal() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withNano(15); + assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withNano(15), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_withNanoOfSecond_noChange() { + ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + ZonedDateTime test = base.withNano(500); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // truncatedTo(TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_truncatedTo_normal() { + assertEquals(TEST_DATE_TIME.truncatedTo(NANOS), TEST_DATE_TIME); + assertEquals(TEST_DATE_TIME.truncatedTo(SECONDS), TEST_DATE_TIME.withNano(0)); + assertEquals(TEST_DATE_TIME.truncatedTo(DAYS), TEST_DATE_TIME.with(LocalTime.MIDNIGHT)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_DATE_TIME.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus/minus + //----------------------------------------------------------------------- + @DataProvider(name="plusDays") + Object[][] data_plusDays() { + return new Object[][] { + // normal + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 0, dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 1, dateTime(2008, 7, 1, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), -1, dateTime(2008, 6, 29, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + // skip over gap + {dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 31, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + {dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 29, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + // land in gap + {dateTime(2008, 3, 29, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + {dateTime(2008, 3, 31, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + // skip over overlap + {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 27, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + {dateTime(2008, 10, 25, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + // land in overlap + {dateTime(2008, 10, 25, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + {dateTime(2008, 10, 27, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS), -1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + }; + } + + @DataProvider(name="plusTime") + Object[][] data_plusTime() { + return new Object[][] { + // normal + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 0, dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 1, dateTime(2008, 7, 1, 0, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), -1, dateTime(2008, 6, 30, 22, 30, 59, 0, OFFSET_0100, ZONE_0100)}, + // gap + {dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + {dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + // overlap + {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS)}, + {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 2, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 3, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + {dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + {dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 2, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)}, + }; + } + + //----------------------------------------------------------------------- + // plus(adjuster) + //----------------------------------------------------------------------- + @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); + } + + @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); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(Duration.ofHours(amount)), expected); + } + + @Test(groups={"tck"}) + public void test_plus_adjuster() { + 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); + assertEquals(t.plus(period), expected); + } + + @Test(groups={"tck"}) + public void test_plus_adjuster_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); + assertEquals(t.plus(duration), expected); + } + + @Test(groups={"tck"}) + public void test_plus_adjuster_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() { + 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); + } + + //----------------------------------------------------------------------- + // plus(long,TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusDays") + public void test_plus_longUnit_days(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(amount, DAYS), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plus_longUnit_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(amount, HOURS), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plus_longUnit_minutes(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(amount * 60, MINUTES), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plus_longUnit_seconds(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(amount * 3600, SECONDS), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plus_longUnit_nanos(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(amount * 3600_000_000_000L, NANOS), expected); + } + + @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + public void test_plus_longUnit_null() { + TEST_DATE_TIME_PARIS.plus(0, null); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusYears(1); + assertEquals(test, ZonedDateTime.of(ldt.plusYears(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_plusYears_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusYears(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMonths() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusMonths(1); + assertEquals(test, ZonedDateTime.of(ldt.plusMonths(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusMonths(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusWeeks() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusWeeks() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusWeeks(1); + assertEquals(test, ZonedDateTime.of(ldt.plusWeeks(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_plusWeeks_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusWeeks(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusDays") + public void test_plusDays(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plusDays(amount), expected); + } + + //----------------------------------------------------------------------- + // plusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plusHours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plusHours(amount), expected); + } + + //----------------------------------------------------------------------- + // plusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plusMinutes(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plusMinutes(amount * 60), expected); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_minutes() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusMinutes(30); + assertEquals(test, ZonedDateTime.of(ldt.plusMinutes(30), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // plusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plusSeconds(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plusSeconds(amount * 3600), expected); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_seconds() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusSeconds(1); + assertEquals(test, ZonedDateTime.of(ldt.plusSeconds(1), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // plusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_plusNanos(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plusNanos(amount * 3600_000_000_000L), expected); + } + + @Test(groups={"tck"}) + public void test_plusNanos_nanos() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.plusNanos(1); + assertEquals(test, ZonedDateTime.of(ldt.plusNanos(1), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // minus(adjuster) + //----------------------------------------------------------------------- + @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); + } + + @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); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_minus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minus(Duration.ofHours(-amount)), expected); + } + + @Test(groups={"tck"}) + public void test_minus_adjuster() { + 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); + assertEquals(t.minus(period), expected); + } + + @Test(groups={"tck"}) + public void test_minus_adjuster_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); + assertEquals(t.minus(duration), expected); + } + + @Test(groups={"tck"}) + public void test_minus_adjuster_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() { + 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); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusYears(1); + assertEquals(test, ZonedDateTime.of(ldt.minusYears(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_minusYears_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusYears(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMonths() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusMonths(1); + assertEquals(test, ZonedDateTime.of(ldt.minusMonths(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusMonths(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusWeeks() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusWeeks() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusWeeks(1); + assertEquals(test, ZonedDateTime.of(ldt.minusWeeks(1), ZONE_0100)); + } + + @Test(groups={"tck"}) + public void test_minusWeeks_zero() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusWeeks(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusDays() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusDays") + public void test_minusDays(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minusDays(-amount), expected); + } + + //----------------------------------------------------------------------- + // minusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_minusHours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minusHours(-amount), expected); + } + + //----------------------------------------------------------------------- + // minusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_minusMinutes(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minusMinutes(-amount * 60), expected); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_minutes() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusMinutes(30); + assertEquals(test, ZonedDateTime.of(ldt.minusMinutes(30), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // minusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_minusSeconds(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minusSeconds(-amount * 3600), expected); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_seconds() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusSeconds(1); + assertEquals(test, ZonedDateTime.of(ldt.minusSeconds(1), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // minusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_minusNanos(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minusNanos(-amount * 3600_000_000_000L), expected); + } + + @Test(groups={"tck"}) + public void test_minusNanos_nanos() { + LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); + ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime test = base.minusNanos(1); + assertEquals(test, ZonedDateTime.of(ldt.minusNanos(1), ZONE_0100)); + } + + //----------------------------------------------------------------------- + // periodUntil(Temporal,TemporalUnit) + //----------------------------------------------------------------------- + // TODO: more tests for period between two different zones + // compare results to OffsetDateTime.periodUntil, especially wrt dates + + @Test(groups={"tck"}, dataProvider="plusDays") + public void test_periodUntil_days(ZonedDateTime base, long expected, ZonedDateTime end) { + assertEquals(base.periodUntil(end, DAYS), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_periodUntil_hours(ZonedDateTime base, long expected, ZonedDateTime end) { + assertEquals(base.periodUntil(end, HOURS), expected); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_periodUntil_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { + assertEquals(base.periodUntil(end, MINUTES), expected * 60); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_periodUntil_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { + assertEquals(base.periodUntil(end, SECONDS), expected * 3600); + } + + @Test(groups={"tck"}, dataProvider="plusTime") + public void test_periodUntil_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { + assertEquals(base.periodUntil(end, NANOS), expected * 3600_000_000_000L); + } + + @Test(groups={"tck"}) + public void test_periodUntil_parisLondon() { + ZonedDateTime midnightLondon = LocalDate.of(2012, 6, 28).atStartOfDay(ZONE_LONDON); + ZonedDateTime midnightParis1 = LocalDate.of(2012, 6, 29).atStartOfDay(ZONE_PARIS); + ZonedDateTime oneAm1 = LocalDateTime.of(2012, 6, 29, 1, 0).atZone(ZONE_PARIS); + ZonedDateTime midnightParis2 = LocalDate.of(2012, 6, 30).atStartOfDay(ZONE_PARIS); + + assertEquals(midnightLondon.periodUntil(midnightParis1, HOURS), 23); + assertEquals(midnightLondon.periodUntil(oneAm1, HOURS), 24); + assertEquals(midnightLondon.periodUntil(midnightParis2, HOURS), 23 + 24); + + assertEquals(midnightLondon.periodUntil(midnightParis1, DAYS), 0); + assertEquals(midnightLondon.periodUntil(oneAm1, DAYS), 1); + assertEquals(midnightLondon.periodUntil(midnightParis2, DAYS), 1); + } + + @Test(groups={"tck"}) + public void test_periodUntil_gap() { + ZonedDateTime before = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); + ZonedDateTime after = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); + + assertEquals(before.periodUntil(after, HOURS), 23); + assertEquals(before.periodUntil(after, DAYS), 1); + } + + @Test(groups={"tck"}) + public void test_periodUntil_overlap() { + ZonedDateTime before = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); + ZonedDateTime after = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); + + assertEquals(before.periodUntil(after, HOURS), 25); + assertEquals(before.periodUntil(after, DAYS), 1); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_periodUntil_differentType() { + TEST_DATE_TIME_PARIS.periodUntil(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS); + } + + @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + public void test_periodUntil_nullTemporal() { + TEST_DATE_TIME_PARIS.periodUntil(null, DAYS); + } + + @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + public void test_periodUntil_nullUnit() { + TEST_DATE_TIME_PARIS.periodUntil(TEST_DATE_TIME_PARIS, null); + } + + //----------------------------------------------------------------------- + // toOffsetDateTime() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toOffsetDateTime() { + assertEquals(TEST_DATE_TIME.toOffsetDateTime(), OffsetDateTime.of(TEST_DATE_TIME.getDateTime(), TEST_DATE_TIME.getOffset())); + } + + //----------------------------------------------------------------------- + // toInstant() + //----------------------------------------------------------------------- + @DataProvider(name="toInstant") + Object[][] data_toInstant() { + return new Object[][] { + {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0), 0L, 0}, + {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 1), 0L, 1}, + {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 999_999_999), 0L, 999_999_999}, + {LocalDateTime.of(1970, 1, 1, 0, 0, 1, 0), 1L, 0}, + {LocalDateTime.of(1970, 1, 1, 0, 0, 1, 1), 1L, 1}, + {LocalDateTime.of(1969, 12, 31, 23, 59, 59, 999999999), -1L, 999_999_999}, + {LocalDateTime.of(1970, 1, 2, 0, 0), 24L * 60L * 60L, 0}, + {LocalDateTime.of(1969, 12, 31, 0, 0), -24L * 60L * 60L, 0}, + }; + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toInstant_UTC(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), expectedEpSec); + assertEquals(test.getNano(), expectedNos); + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toInstant_P0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZONE_0100); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), expectedEpSec - 3600); + assertEquals(test.getNano(), expectedNos); + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toInstant_M0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZONE_M0100); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), expectedEpSec + 3600); + assertEquals(test.getNano(), expectedNos); + } + + //----------------------------------------------------------------------- + // toEpochSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toEpochSecond_afterEpoch() { + LocalDateTime ldt = LocalDateTime.of(1970, 1, 1, 0, 0).plusHours(1); + for (int i = 0; i < 100000; i++) { + ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_PARIS); + assertEquals(a.toEpochSecond(), i); + ldt = ldt.plusSeconds(1); + } + } + + @Test(groups={"tck"}) + public void test_toEpochSecond_beforeEpoch() { + LocalDateTime ldt = LocalDateTime.of(1970, 1, 1, 0, 0).plusHours(1); + for (int i = 0; i < 100000; i++) { + ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_PARIS); + assertEquals(a.toEpochSecond(), -i); + ldt = ldt.minusSeconds(1); + } + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toEpochSecond_UTC(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), expectedEpSec); + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toEpochSecond_P0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZONE_0100); + assertEquals(dt.toEpochSecond(), expectedEpSec - 3600); + } + + @Test(groups={"tck"}, dataProvider="toInstant") + public void test_toEpochSecond_M0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) { + ZonedDateTime dt = ldt.atZone(ZONE_M0100); + assertEquals(dt.toEpochSecond(), expectedEpSec + 3600); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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); + a.compareTo(null); + } + + //----------------------------------------------------------------------- + // isBefore() + //----------------------------------------------------------------------- + @DataProvider(name="IsBefore") + Object[][] data_isBefore() { + return new Object[][] { + {11, 30, ZONE_0100, 11, 31, ZONE_0100, true}, // a is before b due to time + {11, 30, ZONE_0200, 11, 30, ZONE_0100, true}, // a is before b due to offset + {11, 30, ZONE_0200, 10, 30, ZONE_0100, false}, // a is equal b due to same instant + }; + } + + @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); + assertEquals(a.isBefore(b), expected); + assertEquals(b.isBefore(a), false); + assertEquals(a.isBefore(a), false); + assertEquals(b.isBefore(b), false); + } + + @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); + a.isBefore(null); + } + + //----------------------------------------------------------------------- + // isAfter() + //----------------------------------------------------------------------- + @DataProvider(name="IsAfter") + Object[][] data_isAfter() { + return new Object[][] { + {11, 31, ZONE_0100, 11, 30, ZONE_0100, true}, // a is after b due to time + {11, 30, ZONE_0100, 11, 30, ZONE_0200, true}, // a is after b due to offset + {11, 30, ZONE_0200, 10, 30, ZONE_0100, false}, // a is equal b due to same instant + }; + } + + @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); + assertEquals(a.isAfter(b), expected); + assertEquals(b.isAfter(a), false); + assertEquals(a.isAfter(a), false); + assertEquals(b.isAfter(b), false); + } + + @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); + a.isAfter(null); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_equals_true(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) { + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + 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, ZoneId ignored) { + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y + 1, o, d, h, m, s, n), ZONE_0100); + 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, ZoneId ignored) { + h = (h == 23 ? 22 : h); + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h + 1, m, s, n), ZONE_0100); + 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, ZoneId ignored) { + m = (m == 59 ? 58 : m); + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m + 1, s, n), ZONE_0100); + 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, ZoneId ignored) { + s = (s == 59 ? 58 : s); + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s + 1, n), ZONE_0100); + 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, ZoneId ignored) { + n = (n == 999999999 ? 999999998 : n); + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n + 1), ZONE_0100); + 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, ZoneId ignored) { + ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0200); + assertEquals(a.equals(b), false); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_DATE_TIME.equals(TEST_DATE_TIME), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_DATE_TIME.equals("2007-07-15"), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {2008, 6, 30, 11, 30, 59, 0, "Z", "2008-06-30T11:30:59Z"}, + {2008, 6, 30, 11, 30, 59, 0, "+01:00", "2008-06-30T11:30:59+01:00"}, + {2008, 6, 30, 11, 30, 59, 999000000, "Z", "2008-06-30T11:30:59.999Z"}, + {2008, 6, 30, 11, 30, 59, 999000000, "+01:00", "2008-06-30T11:30:59.999+01:00"}, + {2008, 6, 30, 11, 30, 59, 999000, "Z", "2008-06-30T11:30:59.000999Z"}, + {2008, 6, 30, 11, 30, 59, 999000, "+01:00", "2008-06-30T11:30:59.000999+01:00"}, + {2008, 6, 30, 11, 30, 59, 999, "Z", "2008-06-30T11:30:59.000000999Z"}, + {2008, 6, 30, 11, 30, 59, 999, "+01:00", "2008-06-30T11:30:59.000000999+01:00"}, + + {2008, 6, 30, 11, 30, 59, 999, "Europe/London", "2008-06-30T11:30:59.000000999+01:00[Europe/London]"}, + {2008, 6, 30, 11, 30, 59, 999, "Europe/Paris", "2008-06-30T11:30:59.000000999+02:00[Europe/Paris]"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int y, int o, int d, int h, int m, int s, int n, String zoneId, String expected) { + ZonedDateTime t = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZoneId.of(zoneId)); + String str = t.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + ZonedDateTime.of(dateTime(2010, 12, 3, 11, 30), ZONE_PARIS).toString(null); + } + + //------------------------------------------------------------------------- + private static LocalDateTime dateTime( + int year, int month, int dayOfMonth, + int hour, int minute) { + return LocalDateTime.of(year, month, dayOfMonth, hour, minute); + } + + private static LocalDateTime dateTime( + int year, int month, int dayOfMonth, + int hour, int minute, int second, int nanoOfSecond) { + return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); + } + + private static ZonedDateTime dateTime( + int year, int month, int dayOfMonth, + int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset, ZoneId zoneId) { + return ZonedDateTime.ofStrict(LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond), offset, zoneId); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java b/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java new file mode 100644 index 00000000000..c3dc941e491 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java @@ -0,0 +1,251 @@ +/* + * 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) 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.EPOCH_DAY; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +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; + +/** + * The Coptic calendar system. + *

    + * This chronology defines the rules of the Coptic calendar system. + * This calendar system is primarily used in Christian Egypt. + * Dates are aligned such that {@code 0001AM-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}. + *

    + * The fields are defined as follows: + *

      + *
    • era - There are two eras, the current 'Era of the Martyrs' (AM) and the previous era (ERA_ERA_BEFORE_AM). + *
    • year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one. + * For the previous era the year increases from one as time goes backwards. + *
    • proleptic-year - The proleptic year is the same as the year-of-era for the + * current era. For the previous era, years have zero, then negative values. + *
    • month-of-year - There are 13 months in a Coptic year, numbered from 1 to 13. + *
    • day-of-month - There are 30 days in each of the first 12 Coptic months, numbered 1 to 30. + * The 13th month has 5 days, or 6 in a leap year, numbered 1 to 5 or 1 to 6. + *
    • day-of-year - There are 365 days in a standard Coptic year and 366 in a leap year. + * The days are numbered from 1 to 365 or 1 to 366. + *
    • leap-year - Leap years occur every 4 years. + *

    + * + *

    Implementation notes

    + * This class is immutable and thread-safe. + */ +public final class CopticChrono extends Chrono implements Serializable { + + /** + * Singleton instance of the Coptic chronology. + */ + public static final CopticChrono INSTANCE = new CopticChrono(); + /** + * 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; + /** + * 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; + + /** + * Serialization version. + */ + private static final long serialVersionUID = 7291205177830286973L; + /** + * Range of months. + */ + static final ValueRange MOY_RANGE = ValueRange.of(1, 13); + /** + * Range of days. + */ + static final ValueRange DOM_RANGE = ValueRange.of(1, 5, 30); + /** + * Range of days. + */ + static final ValueRange DOM_RANGE_NONLEAP = ValueRange.of(1, 5); + /** + * Range of days. + */ + static final ValueRange DOM_RANGE_LEAP = ValueRange.of(1, 6); + + /** + * Public Constructor to be instantiated by the ServiceLoader + */ + public CopticChrono() { + } + + /** + * Resolve singleton. + * + * @return the singleton instance, not null + */ + private Object readResolve() { + return INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * 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)}. + * + * @return the chronology ID - 'Coptic' + * @see #getCalendarType() + */ + @Override + public String getId() { + return "Coptic"; + } + + /** + * Gets the calendar type of the underlying calendar system - 'coptic'. + *

    + * 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 also be used as part of a locale, accessible via + * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. + * + * @return the calendar system type - 'coptic' + * @see #getId() + */ + @Override + public String getCalendarType() { + return "coptic"; + } + + //----------------------------------------------------------------------- + @Override + public ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth) { + return new CopticDate(prolepticYear, month, dayOfMonth); + } + + @Override + public ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear) { + return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1); + } + + @Override + public ChronoLocalDate date(TemporalAccessor dateTime) { + if (dateTime instanceof CopticDate) { + return (CopticDate) dateTime; + } + return CopticDate.ofEpochDay(dateTime.getLong(EPOCH_DAY)); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified year is a leap year. + *

    + * A Coptic proleptic-year is leap if the remainder after division by four equals three. + * This method does not validate the year passed in, and only has a + * well-defined result for years in the supported range. + * + * @param prolepticYear the proleptic-year to check, not validated for range + * @return true if the year is a leap year + */ + @Override + public boolean isLeapYear(long prolepticYear) { + return Math.floorMod(prolepticYear, 4) == 3; + } + + @Override + public int prolepticYear(Era era, int yearOfEra) { + if (era instanceof CopticEra == false) { + throw new DateTimeException("Era must be CopticEra"); + } + return (era == CopticEra.AM ? yearOfEra : 1 - yearOfEra); + } + + @Override + public Era eraOf(int eraValue) { + return CopticEra.of(eraValue); + } + + @Override + public List> eras() { + return Arrays.>asList(CopticEra.values()); + } + + //----------------------------------------------------------------------- + @Override + public ValueRange range(ChronoField field) { + switch (field) { + case DAY_OF_MONTH: return ValueRange.of(1, 5, 30); + case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 1, 5); + case MONTH_OF_YEAR: return ValueRange.of(1, 13); + case EPOCH_MONTH: return ValueRange.of(-1000, 1000); // TODO + case YEAR_OF_ERA: return ValueRange.of(1, 999, 1000); // TODO + case YEAR: return ValueRange.of(-1000, 1000); // TODO + } + return field.range(); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticDate.java b/jdk/test/java/time/tck/java/time/calendar/CopticDate.java new file mode 100644 index 00000000000..30f1664dd0e --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/CopticDate.java @@ -0,0 +1,340 @@ +/* + * 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) 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.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.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; + +import java.io.Serializable; + +import java.time.DateTimeException; +import java.time.LocalDate; +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; + +/** + * A date in the Coptic calendar system. + *

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

    Implementation notes

    + * This class is immutable and thread-safe. + */ +final class CopticDate + implements ChronoLocalDate, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -7920528871688876868L; + /** + * The difference between the Coptic and Coptic epoch day count. + */ + private static final int EPOCH_DAY_DIFFERENCE = 574971 + 40587; + + /** + * The proleptic year. + */ + private final int prolepticYear; + /** + * The month. + */ + private final short month; + /** + * The day. + */ + private final short day; + + //----------------------------------------------------------------------- + /** + * Creates an instance. + * + * @param epochDay the epoch day to convert based on 1970-01-01 (ISO) + * @return the Coptic date, not null + * @throws DateTimeException if the date is invalid + */ + static CopticDate ofEpochDay(long epochDay) { + epochDay += EPOCH_DAY_DIFFERENCE; + int prolepticYear = (int) (((epochDay * 4) + 1463) / 1461); + int startYearEpochDay = (prolepticYear - 1) * 365 + (prolepticYear / 4); + int doy0 = (int) (epochDay - startYearEpochDay); + int month = doy0 / 30 + 1; + int dom = doy0 % 30 + 1; + return new CopticDate(prolepticYear, month, dom); + } + + private static CopticDate resolvePreviousValid(int prolepticYear, int month, int day) { + if (month == 13 && day > 5) { + day = CopticChrono.INSTANCE.isLeapYear(prolepticYear) ? 6 : 5; + } + return new CopticDate(prolepticYear, month, day); + } + + //----------------------------------------------------------------------- + /** + * Creates an instance. + * + * @param prolepticYear the Coptic proleptic-year + * @param month the Coptic month, from 1 to 13 + * @param dayOfMonth the Coptic day-of-month, from 1 to 30 + * @throws DateTimeException if the date is invalid + */ + CopticDate(int prolepticYear, int month, int dayOfMonth) { + CopticChrono.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; + } else { + range = CopticChrono.DOM_RANGE; + } + range.checkValidValue(dayOfMonth, DAY_OF_MONTH); + + this.prolepticYear = prolepticYear; + this.month = (short) month; + this.day = (short) dayOfMonth; + } + + /** + * Validates the object. + * + * @return the resolved date, not null + */ + private Object readResolve() { + // TODO: validate + return this; + } + + //----------------------------------------------------------------------- + @Override + public CopticChrono getChrono() { + return CopticChrono.INSTANCE; + } + + //----------------------------------------------------------------------- + @Override + public int lengthOfMonth() { + switch (month) { + case 13: + return (isLeapYear() ? 6 : 5); + default: + return 30; + } + } + + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (isSupported(field)) { + ChronoField f = (ChronoField) field; + switch (f) { + case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth()); + case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear()); + case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, month == 13 ? 1 : 5); + case YEAR: + 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); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doRange(this); + } + + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case DAY_OF_WEEK: return Math.floorMod(toEpochDay() + 3, 7) + 1; + case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1; + case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) % 7) + 1; + case DAY_OF_MONTH: return day; + case DAY_OF_YEAR: return (month - 1) * 30 + day; + case EPOCH_DAY: return toEpochDay(); + case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1; + case ALIGNED_WEEK_OF_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) / 7) + 1; + case MONTH_OF_YEAR: return month; + case YEAR_OF_ERA: return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear); + case YEAR: return prolepticYear; + case ERA: return (prolepticYear >= 1 ? 1 : 0); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doGet(this); + } + + @Override + public CopticDate with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + f.checkValidValue(newValue); // TODO: validate value + int nvalue = (int) newValue; + switch (f) { + case DAY_OF_WEEK: return plusDays(newValue - get(ChronoField.DAY_OF_WEEK)); + case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH)); + case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR)); + case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, month, nvalue); + case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1); + case EPOCH_DAY: return ofEpochDay(nvalue); + case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7); + case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7); + case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, day); + case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, month, day); + case YEAR: return resolvePreviousValid(nvalue, month, day); + case ERA: return resolvePreviousValid(1 - prolepticYear, month, day); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doWith(this, newValue); + } + + //----------------------------------------------------------------------- + @Override + public CopticDate plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + ChronoUnit f = (ChronoUnit) unit; + switch (f) { + case DAYS: return plusDays(amountToAdd); + case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7)); + case MONTHS: return plusMonths(amountToAdd); + case YEARS: return plusYears(amountToAdd); + case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10)); + case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); + case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); + } + throw new DateTimeException(unit.getName() + " not valid for CopticDate"); + } + return unit.doPlus(this, amountToAdd); + } + + //----------------------------------------------------------------------- + private CopticDate plusYears(long years) { + return plusMonths(Math.multiplyExact(years, 13)); + } + + private CopticDate plusMonths(long months) { + if (months == 0) { + return this; + } + long curEm = prolepticYear * 13L + (month - 1); + long calcEm = Math.addExact(curEm, months); + int newYear = Math.toIntExact(Math.floorDiv(calcEm, 13)); + int newMonth = (int)Math.floorMod(calcEm, 13) + 1; + return resolvePreviousValid(newYear, newMonth, day); + } + + private CopticDate plusDays(long days) { + if (days == 0) { + return this; + } + return CopticDate.ofEpochDay(Math.addExact(toEpochDay(), days)); + } + + @Override + public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + if (endDateTime instanceof ChronoLocalDate == false) { + throw new DateTimeException("Unable to calculate period between objects of two different types"); + } + ChronoLocalDate end = (ChronoLocalDate) endDateTime; + if (getChrono().equals(end.getChrono()) == 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(); + } + + //----------------------------------------------------------------------- + @Override + public long toEpochDay() { + long year = (long) prolepticYear; + long copticEpochDay = ((year - 1) * 365) + Math.floorDiv(year, 4) + (get(ChronoField.DAY_OF_YEAR) - 1); + return copticEpochDay - EPOCH_DAY_DIFFERENCE; + } + + @Override + public String toString() { + // getLong() reduces chances of exceptions in toString() + long yoe = getLong(YEAR_OF_ERA); + long moy = getLong(MONTH_OF_YEAR); + long dom = getLong(DAY_OF_MONTH); + StringBuilder buf = new StringBuilder(30); + buf.append(getChrono().toString()) + .append(" ") + .append(getEra()) + .append(" ") + .append(yoe) + .append(moy < 10 ? "-0" : "-").append(moy) + .append(dom < 10 ? "-0" : "-").append(dom); + return buf.toString(); + } +} diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticEra.java b/jdk/test/java/time/tck/java/time/calendar/CopticEra.java new file mode 100644 index 00000000000..2526530ed3b --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/CopticEra.java @@ -0,0 +1,210 @@ +/* + * 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) 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.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; + +/** + * An era in the Coptic calendar system. + *

    + * The Coptic calendar system uses the 'Era of the Martyrs'. + * The start of the Coptic epoch {@code 0001-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}. + *

    + * Do not use {@code ordinal()} to obtain the numeric representation of {@code CopticEra}. + * Use {@code getValue()} instead. + * + *

    Implementation notes

    + * This is an immutable and thread-safe enum. + */ +enum CopticEra implements Era { + + /** + * The singleton instance for the era BEFORE_AM, 'Before Era of the Martyrs'. + * This has the numeric value of {@code 0}. + */ + BEFORE_AM, + /** + * The singleton instance for the era AM, 'Era of the Martyrs'. + * This has the numeric value of {@code 1}. + */ + AM; + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code CopticEra} from an {@code int} value. + *

    + * {@code CopticEra} is an enum representing the Coptic eras of BEFORE_AM/AM. + * This factory allows the enum to be obtained from the {@code int} value. + * + * @param era the BEFORE_AM/AM value to represent, from 0 (BEFORE_AM) to 1 (AM) + * @return the era singleton, not null + * @throws DateTimeException if the value is invalid + */ + public static CopticEra of(int era) { + switch (era) { + case 0: + return BEFORE_AM; + case 1: + return AM; + default: + throw new DateTimeException("Invalid era: " + era); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the numeric era {@code int} value. + *

    + * The era BEFORE_AM has the value 0, while the era AM has the value 1. + * + * @return the era value, from 0 (BEFORE_AM) to 1 (AM) + */ + public int getValue() { + return ordinal(); + } + + @Override + public CopticChrono getChrono() { + return CopticChrono.INSTANCE; + } + + // JDK8 default methods: + //----------------------------------------------------------------------- + @Override + public ChronoLocalDate date(int year, int month, int day) { + return getChrono().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); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java b/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java new file mode 100644 index 00000000000..67175c0b06c --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java @@ -0,0 +1,461 @@ +/* + * 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.assertTrue; + +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.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; + +/** + * Test assertions that must be true for all built-in chronologies. + */ +@Test +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}}; + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badWithAdjusterChrono(Chrono 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); + TemporalAdjuster adjuster = new FixedAdjuster(date2); + if (chrono != chrono2) { + try { + date.with(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.with(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusAdjusterChrono(Chrono 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); + if (chrono != chrono2) { + try { + date.plus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.plus(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusAdjusterChrono(Chrono 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); + if (chrono != chrono2) { + try { + date.minus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.minus(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusTemporalUnitChrono(Chrono 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); + TemporalUnit adjuster = new FixedTemporalUnit(date2); + if (chrono != chrono2) { + try { + date.plus(1, adjuster); + Assert.fail("TemporalUnit.doAdd plus should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + 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) { + 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); + TemporalUnit adjuster = new FixedTemporalUnit(date2); + if (chrono != chrono2) { + try { + date.minus(1, adjuster); + Assert.fail("TemporalUnit.doAdd minus should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + 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) { + 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); + TemporalField adjuster = new FixedTemporalField(date2); + if (chrono != chrono2) { + try { + date.with(adjuster, 1); + Assert.fail("TemporalField doSet should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.with(adjuster, 1); + assertEquals(result, date2, "TemporalField doSet failed to replace date"); + } + } + } + + //----------------------------------------------------------------------- + // isBefore, isAfter, isEqual, DATE_COMPARATOR + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="calendars") + public void test_date_comparisons(Chrono chrono) { + List> dates = new ArrayList<>(); + + ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); + + // Insert dates in order, no duplicates + dates.add(date.minus(1000, ChronoUnit.YEARS)); + dates.add(date.minus(100, ChronoUnit.YEARS)); + dates.add(date.minus(10, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(10, ChronoUnit.YEARS)); + dates.add(date.plus(100, ChronoUnit.YEARS)); + 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) { + 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); + for (int j = 0; j < otherDates.size(); j++) { + ChronoLocalDate b = otherDates.get(j); + int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b); + if (i < j) { + assertTrue(cmp < 0, a + " compare " + b); + assertEquals(a.isBefore(b), true, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else if (i > j) { + assertTrue(cmp > 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), true, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else { + assertTrue(cmp == 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), true, a + " isEqual " + b); + } + } + } + } + } + + //----------------------------------------------------------------------- + // Test Serialization of Calendars + //----------------------------------------------------------------------- + @Test( groups={"tck"}, dataProvider="calendars") + public > void test_ChronoSerialization(C chrono) throws Exception { + LocalDate ref = LocalDate.of(1900, 1, 5); + ChronoLocalDate orginal = chrono.date(ref); + 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") + ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); + assertEquals(ser, orginal, "deserialized date is wrong"); + } + + /** + * 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 { + private Temporal datetime; + + FixedAdjuster(Temporal datetime) { + this.datetime = datetime; + } + + @Override + public Temporal adjustInto(Temporal ignore) { + return datetime; + } + + @Override + public Temporal addTo(Temporal ignore) { + return datetime; + } + + @Override + public Temporal subtractFrom(Temporal ignore) { + return datetime; + } + + } + + /** + * FixedTemporalUnit returns a fixed Temporal in all adjustments. + * Construct an FixedTemporalUnit with the Temporal that should be returned from doAdd. + */ + static class FixedTemporalUnit implements TemporalUnit { + private Temporal temporal; + + FixedTemporalUnit(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalUnit"; + } + + @Override + public Duration getDuration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDurationEstimated() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSupported(Temporal temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) this.temporal; + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + 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 doSet. + */ + static class FixedTemporalField implements TemporalField { + private Temporal temporal; + FixedTemporalField(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalField"; + } + + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange range() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(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/calendar/TestChronoLocalDateTime.java new file mode 100644 index 00000000000..e514fb82e02 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java @@ -0,0 +1,469 @@ +/* + * 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.assertTrue; + +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.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.ISOChrono; +import java.time.temporal.TemporalUnit; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test assertions that must be true for all built-in chronologies. + */ +@Test +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}}; + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badWithAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalAdjuster adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.with(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.with(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalAdder adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.plus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.plus(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date time"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalSubtractor adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.minus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.minus(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusTemporalUnitChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalUnit adjuster = new FixedTemporalUnit(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.plus(1, adjuster); + Assert.fail("TemporalUnit.doAdd plus should have thrown a ClassCastException" + cdt + + ", can not be cast to " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.plus(1, adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusTemporalUnitChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalUnit adjuster = new FixedTemporalUnit(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.minus(1, adjuster); + Assert.fail("TemporalUnit.doAdd minus should have thrown a ClassCastException" + cdt.getClass() + + ", can not be cast to " + cdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.minus(1, adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badTemporalFieldChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalField adjuster = new FixedTemporalField(cdt2); + if (chrono != chrono2) { + try { + ChronoLocalDateTime notreached = cdt.with(adjuster, 1); + Assert.fail("TemporalField doSet should have thrown a ClassCastException" + cdt.getClass() + + ", can not be cast to " + cdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.with(adjuster, 1); + assertEquals(result, cdt2, "TemporalField doSet failed to replace date"); + } + } + } + + //----------------------------------------------------------------------- + // isBefore, isAfter, isEqual + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="calendars") + public void test_datetime_comparisons(Chrono chrono) { + List> dates = new ArrayList<>(); + + ChronoLocalDateTime date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN); + + // Insert dates in order, no duplicates + dates.add(date.minus(100, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date.minus(1, ChronoUnit.HOURS)); + dates.add(date.minus(1, ChronoUnit.MINUTES)); + dates.add(date.minus(1, ChronoUnit.SECONDS)); + dates.add(date.minus(1, ChronoUnit.NANOS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.NANOS)); + dates.add(date.plus(1, ChronoUnit.SECONDS)); + dates.add(date.plus(1, ChronoUnit.MINUTES)); + dates.add(date.plus(1, ChronoUnit.HOURS)); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(100, 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 (ChronoLocalDateTime d : dates) { + otherDates.add(chrono2.date(d).atTime(d.getTime())); + } + + // Now compare the sequence of original dates with the sequence of converted dates + for (int i = 0; i < dates.size(); i++) { + ChronoLocalDateTime a = dates.get(i); + for (int j = 0; j < otherDates.size(); j++) { + ChronoLocalDateTime b = otherDates.get(j); + int cmp = ChronoLocalDateTime.DATE_TIME_COMPARATOR.compare(a, b); + if (i < j) { + assertTrue(cmp < 0, a + " compare " + b); + assertEquals(a.isBefore(b), true, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else if (i > j) { + assertTrue(cmp > 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), true, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else { + assertTrue(cmp == 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), true, a + " isEqual " + b); + } + } + } + } + } + + //----------------------------------------------------------------------- + // Test Serialization of ISO via chrono API + //----------------------------------------------------------------------- + @Test( groups={"tck"}, dataProvider="calendars") + public > void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception { + LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3); + ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.getTime()); + 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(); + assertEquals(ser, orginal, "deserialized date is wrong"); + } + + + /** + * 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 { + private Temporal datetime; + + FixedAdjuster(Temporal datetime) { + this.datetime = datetime; + } + + @Override + public Temporal adjustInto(Temporal ignore) { + return datetime; + } + + @Override + public Temporal addTo(Temporal ignore) { + return datetime; + } + + @Override + public Temporal subtractFrom(Temporal ignore) { + return datetime; + } + + } + + /** + * FixedTemporalUnit returns a fixed Temporal in all adjustments. + * Construct an FixedTemporalUnit with the Temporal that should be returned from doAdd. + */ + static class FixedTemporalUnit implements TemporalUnit { + private Temporal temporal; + + FixedTemporalUnit(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalUnit"; + } + + @Override + public Duration getDuration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDurationEstimated() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSupported(Temporal temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) this.temporal; + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + 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 doSet. + */ + static class FixedTemporalField implements TemporalField { + private Temporal temporal; + FixedTemporalField(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalField"; + } + + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange range() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(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/calendar/TestHijrahChrono.java new file mode 100644 index 00000000000..3157e822f09 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java @@ -0,0 +1,236 @@ +/* + * 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 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.temporal.Adjusters; +import java.time.temporal.Chrono; +import java.time.temporal.ISOChrono; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestHijrahChrono { + + //----------------------------------------------------------------------- + // Chrono.ofName("Hijrah") Lookup by name + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_chrono_byName() { + Chrono c = HijrahChrono.INSTANCE; + Chrono test = Chrono.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"); + Assert.assertEquals(test, c); + } + + //----------------------------------------------------------------------- + // creation, toLocalDate() + //----------------------------------------------------------------------- + @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)}, + + {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)}, + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(LocalDate.from(hijrahDate), iso); + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_fromCalendrical(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(HijrahChrono.INSTANCE.date(iso), hijrahDate); + } + + @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) { + HijrahChrono.INSTANCE.date(year, month, dom); + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust1() { + ChronoLocalDate base = HijrahChrono.INSTANCE.date(1728, 10, 28); + ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, HijrahChrono.INSTANCE.date(1728, 10, 29)); + } + + @Test(groups={"tck"}) + public void test_adjust2() { + ChronoLocalDate base = HijrahChrono.INSTANCE.date(1728, 12, 2); + ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, HijrahChrono.INSTANCE.date(1728, 12, 30)); + } + + //----------------------------------------------------------------------- + // HijrahDate.with(Local*) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust_toLocalDate() { + ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4); + ChronoLocalDate test = hijrahDate.with(LocalDate.of(2012, 7, 6)); + assertEquals(test, HijrahChrono.INSTANCE.date(1433, 8, 16)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_adjust_toMonth() { + ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4); + hijrahDate.with(Month.APRIL); + } + + //----------------------------------------------------------------------- + // LocalDate.with(HijrahDate) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_LocalDate_adjustToHijrahDate() { + ChronoLocalDate hijrahDate = HijrahChrono.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); + LocalDateTime test = LocalDateTime.MIN.with(hijrahDate); + assertEquals(test, LocalDateTime.of(2298, 12, 4, 0, 0)); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @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"}, + }; + } + + @Test(dataProvider="toString", groups={"tck"}) + public void test_toString(ChronoLocalDate hijrahDate, String expected) { + assertEquals(hijrahDate.toString(), expected); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equals_true() { + assertTrue(HijrahChrono.INSTANCE.equals(HijrahChrono.INSTANCE)); + } + + @Test(groups="tck") + public void test_equals_false() { + assertFalse(HijrahChrono.INSTANCE.equals(ISOChrono.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 new file mode 100644 index 00000000000..614a3ff0b0a --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java @@ -0,0 +1,284 @@ +/* + * 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/TestMinguoChrono.java b/jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java new file mode 100644 index 00000000000..118f7d89b70 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java @@ -0,0 +1,272 @@ +/* + * 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 java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.calendar.MinguoChrono; +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 org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestMinguoChrono { + + //----------------------------------------------------------------------- + // Chrono.ofName("Minguo") Lookup by name + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_chrono_byName() { + Chrono c = MinguoChrono.INSTANCE; + Chrono test = Chrono.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"); + Assert.assertEquals(test, c); + } + + //----------------------------------------------------------------------- + // creation, toLocalDate() + //----------------------------------------------------------------------- + @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)}, + + {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)}, + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_toLocalDate(ChronoLocalDate 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); + } + + @SuppressWarnings("unused") + @Test(dataProvider="samples", groups={"implementation"}) + public void test_MinguoDate(ChronoLocalDate minguoDate, LocalDate iso) { + ChronoLocalDate hd = minguoDate; + ChronoLocalDateTime hdt = hd.atTime(LocalTime.NOON); + ZoneOffset zo = ZoneOffset.ofHours(1); + ChronoZonedDateTime hzdt = hdt.atZone(zo); + hdt = hdt.plus(1, ChronoUnit.YEARS); + hdt = hdt.plus(1, ChronoUnit.MONTHS); + hdt = hdt.plus(1, ChronoUnit.DAYS); + hdt = hdt.plus(1, ChronoUnit.HOURS); + 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(); + //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); + @SuppressWarnings("unused") + ChronoZonedDateTime h4 = h3.atZone(ZoneOffset.UTC); + } + + @DataProvider(name="badDates") + Object[][] data_badDates() { + return new Object[][] { + {1912, 0, 0}, + + {1912, -1, 1}, + {1912, 0, 1}, + {1912, 14, 1}, + {1912, 15, 1}, + + {1912, 1, -1}, + {1912, 1, 0}, + {1912, 1, 32}, + {1912, 2, 29}, + {1912, 2, 30}, + + {1912, 12, -1}, + {1912, 12, 0}, + {1912, 12, 32}, + }; + } + + @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_badDates(int year, int month, int dom) { + MinguoChrono.INSTANCE.date(year, month, dom); + } + + //----------------------------------------------------------------------- + // with(DateTimeAdjuster) + //----------------------------------------------------------------------- + @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)); + } + + @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.with(Local*) + //----------------------------------------------------------------------- + @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)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_adjust_toMonth() { + ChronoLocalDate minguo = MinguoChrono.INSTANCE.date(1726, 1, 4); + minguo.with(Month.APRIL); + } + + //----------------------------------------------------------------------- + // LocalDate.with(MinguoDate) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_LocalDate_adjustToMinguoDate() { + ChronoLocalDate minguo = MinguoChrono.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); + LocalDateTime test = LocalDateTime.MIN.with(minguo); + assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0)); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @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"}, + }; + } + + @Test(dataProvider="toString", groups={"tck"}) + public void test_toString(ChronoLocalDate minguo, String expected) { + assertEquals(minguo.toString(), expected); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equals_true() { + assertTrue(MinguoChrono.INSTANCE.equals(MinguoChrono.INSTANCE)); + } + + @Test(groups="tck") + public void test_equals_false() { + assertFalse(MinguoChrono.INSTANCE.equals(ISOChrono.INSTANCE)); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java b/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java new file mode 100644 index 00000000000..b7381b77c84 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java @@ -0,0 +1,106 @@ +/* + * 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) 2011-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.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 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. + */ +@Test +public class TestServiceLoader { + + @Test(groups={"tck"}) + public void test_CopticServiceLoader() { + Chrono chrono = Chrono.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/TestThaiBuddhistChrono.java b/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java new file mode 100644 index 00000000000..4d20f570be8 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java @@ -0,0 +1,302 @@ +/* + * 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/format/TCKDateTimeFormatSymbols.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatSymbols.java new file mode 100644 index 00000000000..f2be900c908 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatSymbols.java @@ -0,0 +1,212 @@ +/* + * 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) 2011-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.util.Arrays; +import java.util.Locale; + +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatSymbols. + */ +@Test +public class TCKDateTimeFormatSymbols { + + @Test(groups={"tck"}) + public void test_getAvailableLocales() { + Locale[] locales = DateTimeFormatSymbols.getAvailableLocales(); + assertEquals(locales.length > 0, true); + assertEquals(Arrays.asList(locales).contains(Locale.US), true); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_of_Locale() { + DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.of(Locale.CANADA); + assertEquals(loc1.getZeroDigit(), '0'); + assertEquals(loc1.getPositiveSign(), '+'); + assertEquals(loc1.getNegativeSign(), '-'); + assertEquals(loc1.getDecimalSeparator(), '.'); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_STANDARD() { + DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.STANDARD; + assertEquals(loc1.getZeroDigit(), '0'); + assertEquals(loc1.getPositiveSign(), '+'); + assertEquals(loc1.getNegativeSign(), '-'); + assertEquals(loc1.getDecimalSeparator(), '.'); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_zeroDigit() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.withZeroDigit('A').getZeroDigit(), 'A'); + } + + @Test(groups={"tck"}) + public void test_positiveSign() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.withPositiveSign('A').getPositiveSign(), 'A'); + } + + @Test(groups={"tck"}) + public void test_negativeSign() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.withNegativeSign('A').getNegativeSign(), 'A'); + } + + @Test(groups={"tck"}) + public void test_decimalSeparator() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.withDecimalSeparator('A').getDecimalSeparator(), 'A'); + } + + //----------------------------------------------------------------------- + /* TBD: convertToDigit and convertNumberToI18N are package-private methods + @Test(groups={"tck"}) + public void test_convertToDigit_base() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.convertToDigit('0'), 0); + assertEquals(base.convertToDigit('1'), 1); + assertEquals(base.convertToDigit('9'), 9); + assertEquals(base.convertToDigit(' '), -1); + assertEquals(base.convertToDigit('A'), -1); + } + + @Test(groups={"tck"}) + public void test_convertToDigit_altered() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD.withZeroDigit('A'); + assertEquals(base.convertToDigit('A'), 0); + assertEquals(base.convertToDigit('B'), 1); + assertEquals(base.convertToDigit('J'), 9); + assertEquals(base.convertToDigit(' '), -1); + assertEquals(base.convertToDigit('0'), -1); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_convertNumberToI18N_base() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.convertNumberToI18N("134"), "134"); + } + + @Test(groups={"tck"}) + public void test_convertNumberToI18N_altered() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD.withZeroDigit('A'); + assertEquals(base.convertNumberToI18N("134"), "BDE"); + } + */ + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equalsHashCode1() { + DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD; + DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD; + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_equalsHashCode2() { + DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD.withZeroDigit('A'); + DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD.withZeroDigit('A'); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_equalsHashCode3() { + DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD.withZeroDigit('A'); + DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD.withDecimalSeparator('A'); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + } + + @Test(groups={"tck"}) + public void test_equalsHashCode_bad() { + DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD; + assertEquals(a.equals(""), false); + assertEquals(a.equals(null), false); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_base() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD; + assertEquals(base.toString(), "Symbols[0+-.]"); + } + + @Test(groups={"tck"}) + public void test_toString_altered() { + DateTimeFormatSymbols base = DateTimeFormatSymbols.of(Locale.US).withZeroDigit('A').withDecimalSeparator('@'); + assertEquals(base.toString(), "Symbols[A+-@]"); + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java new file mode 100644 index 00000000000..e206a1f28a7 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java @@ -0,0 +1,705 @@ +/* + * 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 static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +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 java.io.IOException; +import java.text.Format; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.calendar.ThaiBuddhistChrono; +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.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +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. + */ +@Test(groups={"tck"}) +public class TCKDateTimeFormatter { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + 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 DateTimeFormatter fmt; + + @BeforeMethod + public void setUp() { + fmt = new DateTimeFormatterBuilder().appendLiteral("ONE") + .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) + .toFormatter(); + } + + //----------------------------------------------------------------------- + @Test + public void test_withLocale() { + DateTimeFormatter base = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + DateTimeFormatter test = base.withLocale(Locale.GERMAN); + assertEquals(test.getLocale(), Locale.GERMAN); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_withLocale_null() { + DateTimeFormatter base = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + base.withLocale((Locale) null); + } + + //----------------------------------------------------------------------- + @Test + public void test_withChrono() { + 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); + } + + //----------------------------------------------------------------------- + @Test + public void test_withZone() { + DateTimeFormatter test = fmt; + assertEquals(test.getZone(), null); + test = test.withZone(ZoneId.of("Europe/Paris")); + assertEquals(test.getZone(), ZoneId.of("Europe/Paris")); + test = test.withZone(ZoneOffset.UTC); + assertEquals(test.getZone(), ZoneOffset.UTC); + test = test.withZone(null); + assertEquals(test.getZone(), null); + } + + //----------------------------------------------------------------------- + // print + //----------------------------------------------------------------------- + @DataProvider(name="print") + Object[][] data_print() { + 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); + Instant instant = Instant.ofEpochSecond(3600); + return new Object[][] { + {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"}, + {null, null, instant, "::"}, + + {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"}, + {null, ZONE_PARIS, instant, "1970:02:+01:00Europe/Paris"}, + + {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, "::"}, + + {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"}, + }; + } + + @Test(dataProvider="print") + public void test_print_Temporal(Chrono 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); + 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)); + 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(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 + 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); + assertEquals(buf.toString(), "ONE30"); + } + + @Test(expectedExceptions=DateTimeException.class) + 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(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(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(expectedExceptions=IOException.class) // IOException + public void test_print_TemporalAppendable_ioError() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + try { + test.printTo(LocalDate.of(2008, 6, 30), new MockIOExceptionAppendable()); + } catch (DateTimePrintException ex) { + assertEquals(ex.getCause() instanceof IOException, true); + ex.rethrowIOException(); + } + } + + //----------------------------------------------------------------------- + // parse(Query) + //----------------------------------------------------------------------- + @Test + public void test_parse_Query_String() throws Exception { + LocalDate result = DATE_FORMATTER.parse("ONE2012 07 27", LocalDate::from); + assertEquals(result, LocalDate.of(2012, 7, 27)); + } + + @Test + public void test_parse_Query_CharSequence() throws Exception { + LocalDate result = DATE_FORMATTER.parse(new StringBuilder("ONE2012 07 27"), LocalDate::from); + assertEquals(result, LocalDate.of(2012, 7, 27)); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_parse_Query_String_parseError() throws Exception { + try { + DATE_FORMATTER.parse("ONE2012 07 XX", LocalDate::from); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("ONE2012 07 XX"), true); + assertEquals(ex.getParsedString(), "ONE2012 07 XX"); + assertEquals(ex.getErrorIndex(), 11); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_parse_Query_String_parseErrorLongText() throws Exception { + try { + DATE_FORMATTER.parse("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789", LocalDate::from); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true); + assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); + assertEquals(ex.getErrorIndex(), 3); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_parse_Query_String_parseIncomplete() throws Exception { + try { + DATE_FORMATTER.parse("ONE2012 07 27SomethingElse", LocalDate::from); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("ONE2012 07 27SomethingElse"), true); + assertEquals(ex.getParsedString(), "ONE2012 07 27SomethingElse"); + assertEquals(ex.getErrorIndex(), 13); + throw ex; + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parse_Query_String_nullText() throws Exception { + DATE_FORMATTER.parse((String) null, LocalDate::from); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parse_Query_String_nullRule() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parse("30", (TemporalQuery) null); + } + + //----------------------------------------------------------------------- + @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))); + } + + @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); + 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]"); + try { + test.parseBest("2011-06-XX", OffsetDate::from, LocalDate::from); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("XX"), true); + assertEquals(ex.getParsedString(), "2011-06-XX"); + assertEquals(ex.getErrorIndex(), 8); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeParseException.class) + 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); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true); + assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); + assertEquals(ex.getErrorIndex(), 3); + throw ex; + } + } + + @Test(expectedExceptions=DateTimeParseException.class) + 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); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("could not be parsed"), true); + assertEquals(ex.getMessage().contains("ONE30SomethingElse"), true); + assertEquals(ex.getParsedString(), "ONE30SomethingElse"); + assertEquals(ex.getErrorIndex(), 5); + throw ex; + } + } + + @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(expectedExceptions=NullPointerException.class) + public void test_parseBest_String_nullRules() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parseBest("30", (TemporalQuery[]) null); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_parseBest_String_zeroRules() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parseBest("30", new TemporalQuery[0]); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_parseBest_String_oneRule() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parseBest("30", LocalDate::from); + } + + //----------------------------------------------------------------------- + @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 { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + ParsePosition pos = new ParsePosition(0); + DateTimeBuilder result = test.parseToBuilder("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)); + } + + @Test + public void test_parseToBuilder_StringParsePosition_parseError() throws Exception { + 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? + 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(expectedExceptions=NullPointerException.class) + public void test_parseToBuilder_StringParsePosition_nullParsePosition() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parseToBuilder("ONE30", (ParsePosition) null); + } + + @Test(expectedExceptions=IndexOutOfBoundsException.class) + public void test_parseToBuilder_StringParsePosition_invalidPosition() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + ParsePosition pos = new ParsePosition(6); + test.parseToBuilder("ONE30", pos); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_toFormat_format() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + String result = format.format(LocalDate.of(2008, 6, 30)); + assertEquals(result, "ONE30"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_toFormat_format_null() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + format.format(null); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_toFormat_format_notTemporal() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + format.format("Not a Temporal"); + } + + //----------------------------------------------------------------------- + @Test + 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); + } + + @Test(expectedExceptions=ParseException.class) + public void test_toFormat_parseObject_String_parseError() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + try { + format.parseObject("ONEXXX"); + } catch (ParseException ex) { + assertEquals(ex.getMessage().contains("ONEXXX"), true); + assertEquals(ex.getErrorOffset(), 3); + throw ex; + } + } + + @Test(expectedExceptions=ParseException.class) + public void test_toFormat_parseObject_String_parseErrorLongText() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + try { + format.parseObject("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); + } catch (DateTimeParseException ex) { + assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true); + assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); + assertEquals(ex.getErrorIndex(), 3); + throw ex; + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_toFormat_parseObject_String_null() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + format.parseObject((String) null); + } + + //----------------------------------------------------------------------- + @Test + public void test_toFormat_parseObject_StringParsePosition() throws Exception { + 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); + assertEquals(pos.getIndex(), 5); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(result.getFieldValueMap().size(), 1); + assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L); + } + + @Test + public void test_toFormat_parseObject_StringParsePosition_parseError() throws Exception { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + ParsePosition pos = new ParsePosition(0); + TemporalAccessor result = (TemporalAccessor) format.parseObject("ONEXXX", pos); + assertEquals(pos.getIndex(), 0); // TODO: is this right? + assertEquals(pos.getErrorIndex(), 3); + assertEquals(result, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_toFormat_parseObject_StringParsePosition_nullString() throws Exception { + // SimpleDateFormat has this behavior + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + ParsePosition pos = new ParsePosition(0); + format.parseObject((String) null, pos); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_toFormat_parseObject_StringParsePosition_nullParsePosition() throws Exception { + // SimpleDateFormat has this behavior + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + Format format = test.toFormat(); + format.parseObject("ONE30", (ParsePosition) null); + } + + @Test + public void test_toFormat_parseObject_StringParsePosition_invalidPosition_tooBig() throws Exception { + // SimpleDateFormat has this behavior + DateTimeFormatter dtf = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + ParsePosition pos = new ParsePosition(6); + Format test = dtf.toFormat(); + assertNull(test.parseObject("ONE30", pos)); + assertTrue(pos.getErrorIndex() >= 0); + } + + @Test + public void test_toFormat_parseObject_StringParsePosition_invalidPosition_tooSmall() throws Exception { + // SimpleDateFormat throws StringIndexOutOfBoundException + DateTimeFormatter dtf = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + ParsePosition pos = new ParsePosition(-1); + Format test = dtf.toFormat(); + assertNull(test.parseObject("ONE30", pos)); + assertTrue(pos.getErrorIndex() >= 0); + } + + //----------------------------------------------------------------------- + @Test + public void test_toFormat_Query_format() throws Exception { + Format format = BASIC_FORMATTER.toFormat(); + String result = format.format(LocalDate.of(2008, 6, 30)); + assertEquals(result, "ONE30"); + } + + @Test + public void test_toFormat_Query_parseObject_String() throws Exception { + Format format = DATE_FORMATTER.toFormat(LocalDate::from); + LocalDate result = (LocalDate) format.parseObject("ONE2012 07 27"); + assertEquals(result, LocalDate.of(2012, 7, 27)); + } + + @Test(expectedExceptions=ParseException.class) + public void test_toFormat_parseObject_StringParsePosition_dateTimeError() throws Exception { + Format format = DATE_FORMATTER.toFormat(LocalDate::from); + format.parseObject("ONE2012 07 32"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_toFormat_Query() throws Exception { + BASIC_FORMATTER.toFormat(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java new file mode 100644 index 00000000000..1fe79b165eb --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -0,0 +1,856 @@ +/* + * 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 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.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; + +/** + * Test DateTimeFormatterBuilder. + */ +@Test +public class TCKDateTimeFormatterBuilder { + + private DateTimeFormatterBuilder builder; + + @BeforeMethod(groups={"tck"}) + public void setUp() { + builder = new DateTimeFormatterBuilder(); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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"}) + 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"}) + public void test_appendValue_2arg_null() throws Exception { + builder.appendValue(null, 3); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_2arg_widthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 0); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + 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"}) + public void test_appendValue_3arg_nullField() throws Exception { + builder.appendValue(null, 2, 3, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_3arg_minWidthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_3arg_minWidthTooBig() throws Exception { + builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_3arg_maxWidthTooBig() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { + builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + 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"}) + 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"}) + public void test_appendFraction_4arg_nullRule() throws Exception { + builder.appendFraction(null, 1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { + builder.appendFraction(DAY_OF_MONTH, 1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_minTooSmall() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_minTooBig() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_maxTooSmall() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_maxTooBig() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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"}) + 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"}) + public void test_appendText_2arg_nullRule() throws Exception { + builder.appendText(null, TextStyle.SHORT); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + 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"}) + public void test_appendTextMap_nullRule() throws Exception { + builder.appendText(null, new HashMap()); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_appendTextMap_nullStyle() throws Exception { + builder.appendText(MONTH_OF_YEAR, (Map) null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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[][] { + {"+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", groups={"tck"}) + public void test_appendOffset_print(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); + } + + @Test(dataProvider="offsetPatterns", groups={"tck"}) + 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); + } + + @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, groups={"tck"}) + public void test_appendOffset_badPattern(String pattern) throws Exception { + builder.appendOffset(pattern, "Z"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_appendOffset_3arg_nullText() throws Exception { + builder.appendOffset("+HH:MM", null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_appendOffset_3arg_nullPattern() throws Exception { + builder.appendOffset(null, "Z"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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"}) + public void test_appendZoneText_1arg_nullText() throws Exception { + builder.appendZoneText(null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_padNext_1arg_invalidWidth() throws Exception { + builder.padNext(0); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)"); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_padNext_2arg_invalidWidth() throws Exception { + builder.padNext(0, '-'); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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"}) + 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", "Value(Era)"}, + {"GG", "Value(Era,2)"}, + {"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)"}, + {"zzzzz", "ZoneText(FULL)"}, + + {"I", "ZoneId()"}, + {"II", "ZoneId()"}, + {"III", "ZoneId()"}, + {"IIII", "ZoneId()"}, + {"IIIII", "ZoneId()"}, + + {"Z", "Offset('+0000',+HHMM)"}, // SimpleDateFormat compatible + {"ZZ", "Offset('+0000',+HHMM)"}, + {"ZZZ", "Offset('+00:00',+HH:MM)"}, + + {"X", "Offset('Z',+HH)"}, + {"XX", "Offset('Z',+HHMM)"}, + {"XXX", "Offset('Z',+HH:MM)"}, + {"XXXX", "Offset('Z',+HHMMss)"}, + {"XXXXX", "Offset('Z',+HH:MM:ss)"}, + + {"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"}, + + {"RO"}, + + {"p"}, + {"pp"}, + {"p:"}, + + {"f"}, + {"ff"}, + {"f:"}, + {"fy"}, + {"fa"}, + {"fM"}, + + {"ww"}, + {"ee"}, + {"WWW"}, + }; + } + + @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + 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", groups={"tck"}) + 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); + 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/tck/java/time/format/TCKDateTimeFormatters.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java new file mode 100644 index 00000000000..cbb79b981b9 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java @@ -0,0 +1,1276 @@ +/* + * 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 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.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +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.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.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeBuilder; +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.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 org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatters. + */ +@Test +public class TCKDateTimeFormatters { + + @BeforeMethod + public void setUp() { + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_print_nullCalendrical() { + DateTimeFormatters.isoDate().print((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_pattern_String() { + DateTimeFormatter test = DateTimeFormatters.pattern("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"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_pattern_String_null() { + DateTimeFormatters.pattern(null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_pattern_StringLocale() { + DateTimeFormatter test = DateTimeFormatters.pattern("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); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_pattern_StringLocale_nullPattern() { + DateTimeFormatters.pattern(null, Locale.UK); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_pattern_StringLocale_nullLocale() { + DateTimeFormatters.pattern("yyyy", null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoLocalDate") + Object[][] provider_sample_isoLocalDate() { + return new Object[][]{ + {2008, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, DateTimeException.class}, + {null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, null, null, null, null, DateTimeException.class}, + {null, 6, 30, null, null, null, DateTimeException.class}, + + {2008, 6, 30, null, null, "2008-06-30", null}, + {2008, 6, 30, "+01:00", null, "2008-06-30", null}, + {2008, 6, 30, "+01:00", "Europe/Paris", "2008-06-30", null}, + {2008, 6, 30, null, "Europe/Paris", "2008-06-30", null}, + + {123456, 6, 30, null, null, "+123456-06-30", null}, + }; + } + + @Test(dataProvider="sample_isoLocalDate", groups={"tck"}) + public void test_print_isoLocalDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoLocalDate().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoLocalDate", groups={"tck"}) + public void test_parse_isoLocalDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + String input, Class invalid) { + if (input != null) { + DateTimeBuilder expected = createDate(year, month, day); + // offset/zone not expected to be parsed + assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder(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); + 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); + } + + @Test(expectedExceptions = DateTimeException.class, groups={"tck"}) + public void test_parse_isoLocalDate_1000000000_failedCreate() { + LocalDate.parse("+1000000000-08-06"); + } + + @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); + 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); + } + + @Test(expectedExceptions = DateTimeException.class, groups={"tck"}) + public void test_parse_isoLocalDate_M1000000000_failedCreate() { + LocalDate.parse("-1000000000-08-06"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoOffsetDate") + Object[][] provider_sample_isoOffsetDate() { + return new Object[][]{ + {2008, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, DateTimeException.class}, + {null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, null, null, null, null, DateTimeException.class}, + {null, 6, 30, null, null, null, DateTimeException.class}, + + {2008, 6, 30, null, null, null, DateTimeException.class}, + {2008, 6, 30, "+01:00", null, "2008-06-30+01:00", null}, + {2008, 6, 30, "+01:00", "Europe/Paris", "2008-06-30+01:00", null}, + {2008, 6, 30, null, "Europe/Paris", null, DateTimeException.class}, + + {123456, 6, 30, "+01:00", null, "+123456-06-30+01:00", null}, + }; + } + + @Test(dataProvider="sample_isoOffsetDate", groups={"tck"}) + public void test_print_isoOffsetDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoOffsetDate().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoOffsetDate", groups={"tck"}) + public void test_parse_isoOffsetDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + String input, Class invalid) { + if (input != null) { + DateTimeBuilder expected = createDate(year, month, day); + buildCalendrical(expected, offsetId, null); // zone not expected to be parsed + assertParseMatch(DateTimeFormatters.isoOffsetDate().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoDate") + Object[][] provider_sample_isoDate() { + return new Object[][]{ + {2008, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, DateTimeException.class}, + {null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, null, null, null, null, DateTimeException.class}, + {null, 6, 30, null, null, null, DateTimeException.class}, + + {2008, 6, 30, null, null, "2008-06-30", null}, + {2008, 6, 30, "+01:00", null, "2008-06-30+01:00", null}, + {2008, 6, 30, "+01:00", "Europe/Paris", "2008-06-30+01:00", null}, + {2008, 6, 30, null, "Europe/Paris", "2008-06-30", null}, + + {123456, 6, 30, "+01:00", "Europe/Paris", "+123456-06-30+01:00", null}, + }; + } + + @Test(dataProvider="sample_isoDate", groups={"tck"}) + public void test_print_isoDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoDate().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoDate", groups={"tck"}) + public void test_parse_isoDate( + Integer year, Integer month, Integer day, String offsetId, String zoneId, + String input, Class invalid) { + if (input != null) { + DateTimeBuilder expected = createDate(year, month, day); + if (offsetId != null) { + expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + } + assertParseMatch(DateTimeFormatters.isoDate().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoLocalTime") + Object[][] provider_sample_isoLocalTime() { + return new Object[][]{ + {11, null, null, null, null, null, null, DateTimeException.class}, + {null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, DateTimeException.class}, + {null, null, null, 1, null, null, null, DateTimeException.class}, + {null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + + {11, 5, null, null, null, null, "11:05", null}, + {11, 5, 30, null, null, null, "11:05:30", null}, + {11, 5, 30, 500000000, null, null, "11:05:30.5", null}, + {11, 5, 30, 1, null, null, "11:05:30.000000001", null}, + + {11, 5, null, null, "+01:00", null, "11:05", null}, + {11, 5, 30, null, "+01:00", null, "11:05:30", null}, + {11, 5, 30, 500000000, "+01:00", null, "11:05:30.5", null}, + {11, 5, 30, 1, "+01:00", null, "11:05:30.000000001", null}, + + {11, 5, null, null, "+01:00", "Europe/Paris", "11:05", null}, + {11, 5, 30, null, "+01:00", "Europe/Paris", "11:05:30", null}, + {11, 5, 30, 500000000, "+01:00", "Europe/Paris", "11:05:30.5", null}, + {11, 5, 30, 1, "+01:00", "Europe/Paris", "11:05:30.000000001", null}, + + {11, 5, null, null, null, "Europe/Paris", "11:05", null}, + {11, 5, 30, null, null, "Europe/Paris", "11:05:30", null}, + {11, 5, 30, 500000000, null, "Europe/Paris", "11:05:30.5", null}, + {11, 5, 30, 1, null, "Europe/Paris", "11:05:30.000000001", null}, + }; + } + + @Test(dataProvider="sample_isoLocalTime", groups={"tck"}) + public void test_print_isoLocalTime( + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoLocalTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoLocalTime", groups={"tck"}) + public void test_parse_isoLocalTime( + 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); + // offset/zone not expected to be parsed + assertParseMatch(DateTimeFormatters.isoLocalTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoOffsetTime") + Object[][] provider_sample_isoOffsetTime() { + return new Object[][]{ + {11, null, null, null, null, null, null, DateTimeException.class}, + {null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, DateTimeException.class}, + {null, null, null, 1, null, null, null, DateTimeException.class}, + {null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + + {11, 5, null, null, null, null, null, DateTimeException.class}, + {11, 5, 30, null, null, null, null, DateTimeException.class}, + {11, 5, 30, 500000000, null, null, null, DateTimeException.class}, + {11, 5, 30, 1, null, null, null, DateTimeException.class}, + + {11, 5, null, null, "+01:00", null, "11:05+01:00", null}, + {11, 5, 30, null, "+01:00", null, "11:05:30+01:00", null}, + {11, 5, 30, 500000000, "+01:00", null, "11:05:30.5+01:00", null}, + {11, 5, 30, 1, "+01:00", null, "11:05:30.000000001+01:00", null}, + + {11, 5, null, null, "+01:00", "Europe/Paris", "11:05+01:00", null}, + {11, 5, 30, null, "+01:00", "Europe/Paris", "11:05:30+01:00", null}, + {11, 5, 30, 500000000, "+01:00", "Europe/Paris", "11:05:30.5+01:00", null}, + {11, 5, 30, 1, "+01:00", "Europe/Paris", "11:05:30.000000001+01:00", null}, + + {11, 5, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {11, 5, 30, null, null, "Europe/Paris", null, DateTimeException.class}, + {11, 5, 30, 500000000, null, "Europe/Paris", null, DateTimeException.class}, + {11, 5, 30, 1, null, "Europe/Paris", null, DateTimeException.class}, + }; + } + + @Test(dataProvider="sample_isoOffsetTime", groups={"tck"}) + public void test_print_isoOffsetTime( + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoOffsetTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoOffsetTime", groups={"tck"}) + public void test_parse_isoOffsetTime( + 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); + buildCalendrical(expected, offsetId, null); // zoneId is not expected from parse + assertParseMatch(DateTimeFormatters.isoOffsetTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoTime") + Object[][] provider_sample_isoTime() { + return new Object[][]{ + {11, null, null, null, null, null, null, DateTimeException.class}, + {null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, DateTimeException.class}, + {null, null, null, 1, null, null, null, DateTimeException.class}, + {null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + + {11, 5, null, null, null, null, "11:05", null}, + {11, 5, 30, null, null, null, "11:05:30", null}, + {11, 5, 30, 500000000, null, null, "11:05:30.5", null}, + {11, 5, 30, 1, null, null, "11:05:30.000000001", null}, + + {11, 5, null, null, "+01:00", null, "11:05+01:00", null}, + {11, 5, 30, null, "+01:00", null, "11:05:30+01:00", null}, + {11, 5, 30, 500000000, "+01:00", null, "11:05:30.5+01:00", null}, + {11, 5, 30, 1, "+01:00", null, "11:05:30.000000001+01:00", null}, + + {11, 5, null, null, "+01:00", "Europe/Paris", "11:05+01:00", null}, + {11, 5, 30, null, "+01:00", "Europe/Paris", "11:05:30+01:00", null}, + {11, 5, 30, 500000000, "+01:00", "Europe/Paris", "11:05:30.5+01:00", null}, + {11, 5, 30, 1, "+01:00", "Europe/Paris", "11:05:30.000000001+01:00", null}, + + {11, 5, null, null, null, "Europe/Paris", "11:05", null}, + {11, 5, 30, null, null, "Europe/Paris", "11:05:30", null}, + {11, 5, 30, 500000000, null, "Europe/Paris", "11:05:30.5", null}, + {11, 5, 30, 1, null, "Europe/Paris", "11:05:30.000000001", null}, + }; + } + + @Test(dataProvider="sample_isoTime", groups={"tck"}) + public void test_print_isoTime( + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoTime", groups={"tck"}) + public void test_parse_isoTime( + 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); + if (offsetId != null) { + expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + } + assertParseMatch(DateTimeFormatters.isoTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoLocalDateTime") + Object[][] provider_sample_isoLocalDateTime() { + return new Object[][]{ + {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + + {2008, 6, 30, 11, 5, null, null, null, null, "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, null, null, "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, null, null, "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, null, null, "2008-06-30T11:05:30.000000001", null}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", null, "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", null, "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null, "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", null, "2008-06-30T11:05:30.000000001", null}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris", "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris", "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.000000001", null}, + + {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris", "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris", "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris", "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris", "2008-06-30T11:05:30.000000001", null}, + + {123456, 6, 30, 11, 5, null, null, null, null, "+123456-06-30T11:05", null}, + }; + } + + @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"}) + public void test_print_isoLocalDateTime( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoLocalDateTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"}) + public void test_parse_isoLocalDateTime( + Integer year, Integer month, Integer day, + 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); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoOffsetDateTime") + Object[][] provider_sample_isoOffsetDateTime() { + return new Object[][]{ + {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + + {2008, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 500000000, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 1, null, null, null, DateTimeException.class}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", null, "2008-06-30T11:05+01:00", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", null, "2008-06-30T11:05:30+01:00", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null, "2008-06-30T11:05:30.5+01:00", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", null, "2008-06-30T11:05:30.000000001+01:00", null}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris", "2008-06-30T11:05+01:00", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris", "2008-06-30T11:05:30+01:00", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.5+01:00", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.000000001+01:00", null}, + + {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris", null, DateTimeException.class}, + + {123456, 6, 30, 11, 5, null, null, "+01:00", null, "+123456-06-30T11:05+01:00", null}, + }; + } + + @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"}) + public void test_print_isoOffsetDateTime( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoOffsetDateTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"}) + public void test_parse_isoOffsetDateTime( + Integer year, Integer month, Integer day, + 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); + buildCalendrical(expected, offsetId, null); // zone not expected to be parsed + assertParseMatch(DateTimeFormatters.isoOffsetDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoZonedDateTime") + Object[][] provider_sample_isoZonedDateTime() { + return new Object[][]{ + {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + + {2008, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 500000000, null, null, null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 1, null, null, null, DateTimeException.class}, + + // allow OffsetDateTime (no harm comes of this AFAICT) + {2008, 6, 30, 11, 5, null, null, "+01:00", null, "2008-06-30T11:05+01:00", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", null, "2008-06-30T11:05:30+01:00", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null, "2008-06-30T11:05:30.5+01:00", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", null, "2008-06-30T11:05:30.000000001+01:00", null}, + + // ZonedDateTime with ZoneId of ZoneOffset + {2008, 6, 30, 11, 5, null, null, "+01:00", "+01:00", "2008-06-30T11:05+01:00", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", "+01:00", "2008-06-30T11:05:30+01:00", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "+01:00", "2008-06-30T11:05:30.5+01:00", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", "+01:00", "2008-06-30T11:05:30.000000001+01:00", null}, + + // ZonedDateTime with ZoneId of ZoneRegion + {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris", "2008-06-30T11:05+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris", "2008-06-30T11:05:30+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null}, + + // offset required + {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris", null, DateTimeException.class}, + + {123456, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris", "+123456-06-30T11:05+01:00[Europe/Paris]", null}, + }; + } + + @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"}) + public void test_print_isoZonedDateTime( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoZonedDateTime().print(test); + fail(test.toString()); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"}) + public void test_parse_isoZonedDateTime( + Integer year, Integer month, Integer day, + 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); + if (offsetId.equals(zoneId)) { + buildCalendrical(expected, offsetId, null); + } else { + buildCalendrical(expected, offsetId, zoneId); + } + assertParseMatch(DateTimeFormatters.isoZonedDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="sample_isoDateTime") + Object[][] provider_sample_isoDateTime() { + return new Object[][]{ + {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class}, + {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class}, + {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class}, + {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class}, + {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class}, + {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class}, + + {2008, 6, 30, 11, 5, null, null, null, null, "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, null, null, "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, null, null, "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, null, null, "2008-06-30T11:05:30.000000001", null}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", null, "2008-06-30T11:05+01:00", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", null, "2008-06-30T11:05:30+01:00", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null, "2008-06-30T11:05:30.5+01:00", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", null, "2008-06-30T11:05:30.000000001+01:00", null}, + + {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris", "2008-06-30T11:05+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris", "2008-06-30T11:05:30+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null}, + {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris", "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null}, + + {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris", "2008-06-30T11:05", null}, + {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris", "2008-06-30T11:05:30", null}, + {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris", "2008-06-30T11:05:30.5", null}, + {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris", "2008-06-30T11:05:30.000000001", null}, + + {123456, 6, 30, 11, 5, null, null, null, null, "+123456-06-30T11:05", null}, + }; + } + + @Test(dataProvider="sample_isoDateTime", groups={"tck"}) + public void test_print_isoDateTime( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, + 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); + } else { + try { + DateTimeFormatters.isoDateTime().print(test); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + @Test(dataProvider="sample_isoDateTime", groups={"tck"}) + public void test_parse_isoDateTime( + Integer year, Integer month, Integer day, + 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); + if (offsetId != null) { + expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + if (zoneId != null) { + expected.addCalendrical(ZoneId.of(zoneId)); + } + } + assertParseMatch(DateTimeFormatters.isoDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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"); + } + + @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"); + } + + @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"); + } + + @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"); + } + + @Test(groups={"tck"}) + public void test_print_isoOrdinalDate_fields() { + TemporalAccessor test = new DateTimeBuilder(YEAR, 2008).addFieldValue(DAY_OF_YEAR, 231); + assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-231"); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_print_isoOrdinalDate_missingField() { + TemporalAccessor test = Year.of(2008); + DateTimeFormatters.isoOrdinalDate().print(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); + } + + @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); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @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"); + } + + @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"); + } + + @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"); + } + + @Test(expectedExceptions=DateTimePrintException.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); + } + + @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"); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_print_basicIsoDate_missingField() { + TemporalAccessor test = YearMonth.of(2008, 6); + DateTimeFormatters.basicIsoDate().print(test); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_parse_basicIsoDate() { + LocalDate expected = LocalDate.of(2008, 6, 3); + assertEquals(DateTimeFormatters.basicIsoDate().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); + } catch (DateTimeParseException ex) { + assertEquals(ex.getErrorIndex(), 0); + assertEquals(ex.getParsedString(), "+1234560603"); + throw ex; + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="weekDate") + Iterator weekDate() { + return new Iterator() { + private ZonedDateTime date = ZonedDateTime.of(LocalDateTime.of(2003, 12, 29, 11, 5, 30), ZoneId.of("Europe/Paris")); + private ZonedDateTime endDate = date.withYear(2005).withMonth(1).withDayOfMonth(2); + private int week = 1; + private int day = 1; + + public boolean hasNext() { + return !date.isAfter(endDate); + } + public Object[] next() { + StringBuilder sb = new StringBuilder("2004-W"); + if (week < 10) { + sb.append('0'); + } + sb.append(week).append('-').append(day).append(date.getOffset()); + Object[] ret = new Object[] {date, sb.toString()}; + date = date.plusDays(1); + day += 1; + if (day == 8) { + day = 1; + week++; + } + return ret; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Test(dataProvider="weekDate", groups={"tck"}) + public void test_print_isoWeekDate(TemporalAccessor test, String expected) { + assertEquals(DateTimeFormatters.isoWeekDate().print(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"); + } + + @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"); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_print_isoWeekDate_missingField() { + TemporalAccessor test = YearMonth.of(2008, 6); + DateTimeFormatters.isoWeekDate().print(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); + } + + @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); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="rfc") + Object[][] data_rfc() { + return new Object[][] { + {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", "Tue, 3 Jun 2008 11:05:30 GMT"}, + {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "Z", "Mon, 30 Jun 2008 11:05:30 GMT"}, + {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Tue, 3 Jun 2008 11:05:30 +0200"}, + {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "-03:00", "Mon, 30 Jun 2008 11:05:30 -0300"}, + }; + } + + @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); + } + + @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); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_print_rfc1123_missingField() { + TemporalAccessor test = YearMonth.of(2008, 6); + DateTimeFormatters.rfc1123().print(test); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + private DateTimeBuilder createDate(Integer year, Integer month, Integer day) { + DateTimeBuilder test = new DateTimeBuilder(); + if (year != null) { + test.addFieldValue(YEAR, year); + } + if (month != null) { + test.addFieldValue(MONTH_OF_YEAR, month); + } + if (day != null) { + test.addFieldValue(DAY_OF_MONTH, day); + } + return test; + } + + private DateTimeBuilder createTime(Integer hour, Integer min, Integer sec, Integer nano) { + DateTimeBuilder test = new DateTimeBuilder(); + if (hour != null) { + test.addFieldValue(HOUR_OF_DAY, hour); + } + if (min != null) { + test.addFieldValue(MINUTE_OF_HOUR, min); + } + if (sec != null) { + test.addFieldValue(SECOND_OF_MINUTE, sec); + } + if (nano != null) { + test.addFieldValue(NANO_OF_SECOND, nano); + } + return test; + } + + private DateTimeBuilder createDateTime( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano) { + DateTimeBuilder test = new DateTimeBuilder(); + if (year != null) { + test.addFieldValue(YEAR, year); + } + if (month != null) { + test.addFieldValue(MONTH_OF_YEAR, month); + } + if (day != null) { + test.addFieldValue(DAY_OF_MONTH, day); + } + if (hour != null) { + test.addFieldValue(HOUR_OF_DAY, hour); + } + if (min != null) { + test.addFieldValue(MINUTE_OF_HOUR, min); + } + if (sec != null) { + test.addFieldValue(SECOND_OF_MINUTE, sec); + } + if (nano != null) { + test.addFieldValue(NANO_OF_SECOND, nano); + } + return test; + } + + private TemporalAccessor buildAccessor( + Integer year, Integer month, Integer day, + Integer hour, Integer min, Integer sec, Integer nano, + String offsetId, String zoneId) { + MockAccessor mock = new MockAccessor(); + if (year != null) { + mock.fields.put(YEAR, (long) year); + } + if (month != null) { + mock.fields.put(MONTH_OF_YEAR, (long) month); + } + if (day != null) { + mock.fields.put(DAY_OF_MONTH, (long) day); + } + if (hour != null) { + mock.fields.put(HOUR_OF_DAY, (long) hour); + } + if (min != null) { + mock.fields.put(MINUTE_OF_HOUR, (long) min); + } + if (sec != null) { + mock.fields.put(SECOND_OF_MINUTE, (long) sec); + } + if (nano != null) { + mock.fields.put(NANO_OF_SECOND, (long) nano); + } + mock.setOffset(offsetId); + mock.setZone(zoneId); + return mock; + } + + private TemporalAccessor buildAccessor(LocalDateTime base, String offsetId, String zoneId) { + MockAccessor mock = new MockAccessor(); + mock.setFields(base); + mock.setOffset(offsetId); + mock.setZone(zoneId); + return mock; + } + + private TemporalAccessor buildAccessor(LocalDate base, String offsetId, String zoneId) { + MockAccessor mock = new MockAccessor(); + mock.setFields(base); + mock.setOffset(offsetId); + mock.setZone(zoneId); + return mock; + } + + private void buildCalendrical(DateTimeBuilder cal, String offsetId, String zoneId) { + if (offsetId != null) { + cal.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + } + if (zoneId != null) { + cal.addCalendrical(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); + } + + //------------------------------------------------------------------------- + Map fields = new HashMap<>(); + ZoneId zoneId; + static class MockAccessor implements TemporalAccessor { + Map fields = new HashMap<>(); + ZoneId zoneId; + + void setFields(LocalDate dt) { + if (dt != null) { + fields.put(YEAR, (long) dt.getYear()); + fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue()); + 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)); + } + } + + void setFields(LocalDateTime dt) { + if (dt != null) { + fields.put(YEAR, (long) dt.getYear()); + fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue()); + 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(HOUR_OF_DAY, (long) dt.getHour()); + fields.put(MINUTE_OF_HOUR, (long) dt.getMinute()); + fields.put(SECOND_OF_MINUTE, (long) dt.getSecond()); + fields.put(NANO_OF_SECOND, (long) dt.getNano()); + } + } + + void setOffset(String offsetId) { + if (offsetId != null) { + this.fields.put(OFFSET_SECONDS, (long) ZoneOffset.of(offsetId).getTotalSeconds()); + } + } + + void setZone(String zoneId) { + if (zoneId != null) { + this.zoneId = ZoneId.of(zoneId); + } + } + + @Override + public boolean isSupported(TemporalField field) { + return fields.containsKey(field); + } + + @Override + public long getLong(TemporalField field) { + try { + return fields.get(field); + } catch (NullPointerException ex) { + throw new DateTimeException("Field missing: " + field); + } + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.zoneId()) { + return (R) zoneId; + } + return TemporalAccessor.super.query(query); + } + + @Override + public String toString() { + return fields + (zoneId != null ? " " + zoneId : ""); + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java new file mode 100644 index 00000000000..0117629f8cb --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java @@ -0,0 +1,101 @@ +/* + * 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 new file mode 100644 index 00000000000..5af0ebf41a9 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.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) 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 tck.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; +import static org.testng.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import java.time.LocalDateTime; +import java.time.Month; +import java.time.temporal.TemporalField; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test text printing. + */ +@Test +public class TCKDateTimeTextPrinting { + + private DateTimeFormatterBuilder builder; + + @BeforeMethod(groups={"tck"}) + public void setUp() { + builder = new DateTimeFormatterBuilder(); + } + + //----------------------------------------------------------------------- + @DataProvider(name="printText") + Object[][] data_text() { + return new Object[][] { + {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"}, + {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"}, + {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"}, + {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"}, + {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"}, + + {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"}, + {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"}, + {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"}, + {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"}, + {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"}, + {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"}, + {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"}, + + {DAY_OF_MONTH, TextStyle.FULL, 1, "1"}, + {DAY_OF_MONTH, TextStyle.FULL, 2, "2"}, + {DAY_OF_MONTH, TextStyle.FULL, 3, "3"}, + {DAY_OF_MONTH, TextStyle.FULL, 28, "28"}, + {DAY_OF_MONTH, TextStyle.FULL, 29, "29"}, + {DAY_OF_MONTH, TextStyle.FULL, 30, "30"}, + {DAY_OF_MONTH, TextStyle.FULL, 31, "31"}, + + {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"}, + {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"}, + {DAY_OF_MONTH, TextStyle.SHORT, 3, "3"}, + {DAY_OF_MONTH, TextStyle.SHORT, 28, "28"}, + {DAY_OF_MONTH, TextStyle.SHORT, 29, "29"}, + {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"}, + {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"}, + + {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"}, + {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"}, + + {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"}, + }; + } + + @Test(dataProvider="printText", groups={"tck"}) + public void test_appendText2arg_print(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); + assertEquals(text, expected); + } + + @Test(dataProvider="printText", groups={"tck"}) + public void test_appendText1arg_print(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); + assertEquals(text, expected); + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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); + assertEquals(text, "janvier"); + } + + @Test(groups={"tck"}) + 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); + assertEquals(text, "janv."); + } + + //----------------------------------------------------------------------- + @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(); + 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())); + } + } + + @Test(groups={"tck"}) + public void test_appendTextMap_DOM() throws Exception { + Map map = new HashMap(); + map.put(1L, "1st"); + map.put(2L, "2nd"); + map.put(3L, "3rd"); + 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"); + } + + @Test(groups={"tck"}) + public void test_appendTextMapIncomplete() throws Exception { + Map map = new HashMap(); + map.put(1L, "JNY"); + builder.appendText(MONTH_OF_YEAR, map); + DateTimeFormatter f = builder.toFormatter(); + LocalDateTime dt = LocalDateTime.of(2010, 2, 1, 0, 0); + assertEquals(f.print(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 new file mode 100644 index 00000000000..d6f5f1619bb --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java @@ -0,0 +1,164 @@ +/* + * 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 java.time.format.*; + +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.temporal.TemporalField; +import java.time.temporal.WeekFields; + +import test.java.time.format.AbstractTestPrinterParser; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test TCKLocalizedFieldParser. + */ +@Test(groups={"tck"}) +public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @DataProvider(name="FieldPatterns") + Object[][] provider_fieldPatterns() { + return new Object[][] { + {"e", "6", 0, 1, 6}, + {"w", "3", 0, 1, 3}, + {"W", "29", 0, 2, 29}, + {"WW", "29", 0, 2, 29}, + }; + } + + @Test(dataProvider="FieldPatterns",groups={"tck"}) + public void test_parse_textField(String pattern, String text, int pos, int expectedPos, long expectedValue) { + WeekFields weekDef = WeekFields.of(locale); + TemporalField field = null; + switch(pattern.charAt(0)) { + case 'e' : + field = weekDef.dayOfWeek(); + break; + case 'w': + field = weekDef.weekOfMonth(); + break; + case 'W': + field = weekDef.weekOfYear(); + break; + default: + throw new IllegalStateException("bad format letter from pattern"); + } + ParsePosition ppos = new ParsePosition(pos); + DateTimeFormatterBuilder b + = new DateTimeFormatterBuilder().appendPattern(pattern); + DateTimeFormatter dtf = b.toFormatter(locale); + DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos); + if (ppos.getErrorIndex() != -1) { + assertEquals(ppos.getErrorIndex(), expectedPos); + } else { + assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position"); + long value = dtb.getLong(field); + assertEquals(value, expectedValue, "Value incorrect for " + field); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="LocalDatePatterns") + Object[][] provider_patternLocalDate() { + return new Object[][] { + {"e w M y", "1 1 1 2012", 0, 10, LocalDate.of(2012, 1, 1)}, + {"e w M y", "1 2 1 2012", 0, 10, LocalDate.of(2012, 1, 8)}, + {"e w M y", "2 2 1 2012", 0, 10, LocalDate.of(2012, 1, 9)}, + {"e w M y", "3 2 1 2012", 0, 10, LocalDate.of(2012, 1, 10)}, + {"e w M y", "1 3 1 2012", 0, 10, LocalDate.of(2012, 1, 15)}, + {"e w M y", "2 3 1 2012", 0, 10, LocalDate.of(2012, 1, 16)}, + {"e w M y", "6 2 1 2012", 0, 10, LocalDate.of(2012, 1, 13)}, + {"e w M y", "6 2 7 2012", 0, 10, LocalDate.of(2012, 7, 13)}, + {"e W y", "6 29 2012", 0, 9, LocalDate.of(2012, 7, 20)}, + {"'Date: 'y-MM', day-of-week: 'e', week-of-month: 'w", + "Date: 2012-07, day-of-week: 6, week-of-month: 3", 0, 47, LocalDate.of(2012, 7, 20)}, + {"'Date: 'y', day-of-week: 'e', week-of-year: 'W", + "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); + DateTimeFormatter dtf = b.toFormatter(locale); + DateTimeBuilder dtb = dtf.parseToBuilder(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(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 new file mode 100644 index 00000000000..dac65b6b110 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java @@ -0,0 +1,105 @@ +/* + * 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 java.time.format.*; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.time.LocalDate; + +import test.java.time.format.AbstractTestPrinterParser; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test LocalizedFieldPrinterParser. + */ +@Test(groups={"tck"}) +public class TCKLocalizedFieldPrinter extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @DataProvider(name="Patterns") + Object[][] provider_pad() { + return new Object[][] { + {"e", "6"}, + {"w", "3"}, + {"W", "29"}, + {"WW", "29"}, + {"'Date: 'y-MM-d', week-of-month: 'w', week-of-year: 'W", + "Date: 2012-07-20, week-of-month: 3, week-of-year: 29"}, + + }; + } + + //----------------------------------------------------------------------- + @Test(dataProvider="Patterns",groups={"tck"}) + public void test_localizedDayOfWeek(String pattern, String expected) { + DateTimeFormatterBuilder b + = new DateTimeFormatterBuilder().appendPattern(pattern); + LocalDate date = LocalDate.of(2012, 7, 20); + + String result = b.toFormatter(locale).print(date); + assertEquals(result, expected, "Wrong output for pattern '" + pattern + "'."); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java b/jdk/test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java new file mode 100644 index 00000000000..231a16b5674 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java @@ -0,0 +1,601 @@ +/* + * 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) 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 java.time.temporal.*; + +import static java.time.DayOfWeek.MONDAY; +import static java.time.DayOfWeek.TUESDAY; +import static java.time.Month.DECEMBER; +import static java.time.Month.JANUARY; +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.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Month; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Adjusters. + */ +@Test +public class TCKDateTimeAdjusters { + + //----------------------------------------------------------------------- + // firstDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_firstDayOfMonth() { + assertNotNull(Adjusters.firstDayOfMonth()); + } + + @Test(groups={"tck"}) + public void test_firstDayOfMonth_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfMonth().adjustInto(date); + assertEquals(test.getYear(), 2007); + assertEquals(test.getMonth(), month); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + @Test(groups={"tck"}) + public void test_firstDayOfMonth_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfMonth().adjustInto(date); + assertEquals(test.getYear(), 2008); + assertEquals(test.getMonth(), month); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + //----------------------------------------------------------------------- + // lastDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_lastDayOfMonth() { + assertNotNull(Adjusters.lastDayOfMonth()); + } + + @Test(groups={"tck"}) + public void test_lastDayOfMonth_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.lastDayOfMonth().adjustInto(date); + assertEquals(test.getYear(), 2007); + assertEquals(test.getMonth(), month); + assertEquals(test.getDayOfMonth(), month.length(false)); + } + } + } + + @Test(groups={"tck"}) + public void test_lastDayOfMonth_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.lastDayOfMonth().adjustInto(date); + assertEquals(test.getYear(), 2008); + assertEquals(test.getMonth(), month); + assertEquals(test.getDayOfMonth(), month.length(true)); + } + } + } + + //----------------------------------------------------------------------- + // firstDayOfNextMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_firstDayOfNextMonth() { + assertNotNull(Adjusters.firstDayOfNextMonth()); + } + + @Test(groups={"tck"}) + public void test_firstDayOfNextMonth_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfNextMonth().adjustInto(date); + assertEquals(test.getYear(), month == DECEMBER ? 2008 : 2007); + assertEquals(test.getMonth(), month.plus(1)); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + @Test(groups={"tck"}) + public void test_firstDayOfNextMonth_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfNextMonth().adjustInto(date); + assertEquals(test.getYear(), month == DECEMBER ? 2009 : 2008); + assertEquals(test.getMonth(), month.plus(1)); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + //----------------------------------------------------------------------- + // firstDayOfYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_firstDayOfYear() { + assertNotNull(Adjusters.firstDayOfYear()); + } + + @Test(groups={"tck"}) + public void test_firstDayOfYear_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfYear().adjustInto(date); + assertEquals(test.getYear(), 2007); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + @Test(groups={"tck"}) + public void test_firstDayOfYear_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfYear().adjustInto(date); + assertEquals(test.getYear(), 2008); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + //----------------------------------------------------------------------- + // lastDayOfYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_lastDayOfYear() { + assertNotNull(Adjusters.lastDayOfYear()); + } + + @Test(groups={"tck"}) + public void test_lastDayOfYear_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.lastDayOfYear().adjustInto(date); + assertEquals(test.getYear(), 2007); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + } + } + } + + @Test(groups={"tck"}) + public void test_lastDayOfYear_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.lastDayOfYear().adjustInto(date); + assertEquals(test.getYear(), 2008); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + } + } + } + + //----------------------------------------------------------------------- + // firstDayOfNextYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_firstDayOfNextYear() { + assertNotNull(Adjusters.firstDayOfNextYear()); + } + + @Test(groups={"tck"}) + public void test_firstDayOfNextYear_nonLeap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfNextYear().adjustInto(date); + assertEquals(test.getYear(), 2008); + assertEquals(test.getMonth(), JANUARY); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + @Test(groups={"tck"}) + public void test_firstDayOfNextYear_leap() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(true); i++) { + LocalDate date = date(2008, month, i); + LocalDate test = (LocalDate) Adjusters.firstDayOfNextYear().adjustInto(date); + assertEquals(test.getYear(), 2009); + assertEquals(test.getMonth(), JANUARY); + assertEquals(test.getDayOfMonth(), 1); + } + } + } + + //----------------------------------------------------------------------- + // dayOfWeekInMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_dayOfWeekInMonth() { + assertNotNull(Adjusters.dayOfWeekInMonth(1, MONDAY)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_dayOfWeekInMonth_nullDayOfWeek() { + Adjusters.dayOfWeekInMonth(1, null); + } + + @DataProvider(name = "dayOfWeekInMonth_positive") + Object[][] data_dayOfWeekInMonth_positive() { + return new Object[][] { + {2011, 1, TUESDAY, date(2011, 1, 4)}, + {2011, 2, TUESDAY, date(2011, 2, 1)}, + {2011, 3, TUESDAY, date(2011, 3, 1)}, + {2011, 4, TUESDAY, date(2011, 4, 5)}, + {2011, 5, TUESDAY, date(2011, 5, 3)}, + {2011, 6, TUESDAY, date(2011, 6, 7)}, + {2011, 7, TUESDAY, date(2011, 7, 5)}, + {2011, 8, TUESDAY, date(2011, 8, 2)}, + {2011, 9, TUESDAY, date(2011, 9, 6)}, + {2011, 10, TUESDAY, date(2011, 10, 4)}, + {2011, 11, TUESDAY, date(2011, 11, 1)}, + {2011, 12, TUESDAY, date(2011, 12, 6)}, + }; + } + + @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_positive") + public void test_dayOfWeekInMonth_positive(int year, int month, DayOfWeek dow, LocalDate expected) { + for (int ordinal = 1; ordinal <= 5; ordinal++) { + for (int day = 1; day <= Month.of(month).length(false); day++) { + LocalDate date = date(year, month, day); + LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(ordinal, dow).adjustInto(date); + assertEquals(test, expected.plusWeeks(ordinal - 1)); + } + } + } + + @DataProvider(name = "dayOfWeekInMonth_zero") + Object[][] data_dayOfWeekInMonth_zero() { + return new Object[][] { + {2011, 1, TUESDAY, date(2010, 12, 28)}, + {2011, 2, TUESDAY, date(2011, 1, 25)}, + {2011, 3, TUESDAY, date(2011, 2, 22)}, + {2011, 4, TUESDAY, date(2011, 3, 29)}, + {2011, 5, TUESDAY, date(2011, 4, 26)}, + {2011, 6, TUESDAY, date(2011, 5, 31)}, + {2011, 7, TUESDAY, date(2011, 6, 28)}, + {2011, 8, TUESDAY, date(2011, 7, 26)}, + {2011, 9, TUESDAY, date(2011, 8, 30)}, + {2011, 10, TUESDAY, date(2011, 9, 27)}, + {2011, 11, TUESDAY, date(2011, 10, 25)}, + {2011, 12, TUESDAY, date(2011, 11, 29)}, + }; + } + + @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_zero") + public void test_dayOfWeekInMonth_zero(int year, int month, DayOfWeek dow, LocalDate expected) { + for (int day = 1; day <= Month.of(month).length(false); day++) { + LocalDate date = date(year, month, day); + LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(0, dow).adjustInto(date); + assertEquals(test, expected); + } + } + + @DataProvider(name = "dayOfWeekInMonth_negative") + Object[][] data_dayOfWeekInMonth_negative() { + return new Object[][] { + {2011, 1, TUESDAY, date(2011, 1, 25)}, + {2011, 2, TUESDAY, date(2011, 2, 22)}, + {2011, 3, TUESDAY, date(2011, 3, 29)}, + {2011, 4, TUESDAY, date(2011, 4, 26)}, + {2011, 5, TUESDAY, date(2011, 5, 31)}, + {2011, 6, TUESDAY, date(2011, 6, 28)}, + {2011, 7, TUESDAY, date(2011, 7, 26)}, + {2011, 8, TUESDAY, date(2011, 8, 30)}, + {2011, 9, TUESDAY, date(2011, 9, 27)}, + {2011, 10, TUESDAY, date(2011, 10, 25)}, + {2011, 11, TUESDAY, date(2011, 11, 29)}, + {2011, 12, TUESDAY, date(2011, 12, 27)}, + }; + } + + @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_negative") + public void test_dayOfWeekInMonth_negative(int year, int month, DayOfWeek dow, LocalDate expected) { + for (int ordinal = 0; ordinal < 5; ordinal++) { + for (int day = 1; day <= Month.of(month).length(false); day++) { + LocalDate date = date(year, month, day); + LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(-1 - ordinal, dow).adjustInto(date); + assertEquals(test, expected.minusWeeks(ordinal)); + } + } + } + + //----------------------------------------------------------------------- + // firstInMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_firstInMonth() { + assertNotNull(Adjusters.firstInMonth(MONDAY)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_firstInMonth_nullDayOfWeek() { + Adjusters.firstInMonth(null); + } + + @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_positive") + public void test_firstInMonth(int year, int month, DayOfWeek dow, LocalDate expected) { + for (int day = 1; day <= Month.of(month).length(false); day++) { + LocalDate date = date(year, month, day); + LocalDate test = (LocalDate) Adjusters.firstInMonth(dow).adjustInto(date); + assertEquals(test, expected, "day-of-month=" + day); + } + } + + //----------------------------------------------------------------------- + // lastInMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_lastInMonth() { + assertNotNull(Adjusters.lastInMonth(MONDAY)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_lastInMonth_nullDayOfWeek() { + Adjusters.lastInMonth(null); + } + + @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_negative") + public void test_lastInMonth(int year, int month, DayOfWeek dow, LocalDate expected) { + for (int day = 1; day <= Month.of(month).length(false); day++) { + LocalDate date = date(year, month, day); + LocalDate test = (LocalDate) Adjusters.lastInMonth(dow).adjustInto(date); + assertEquals(test, expected, "day-of-month=" + day); + } + } + + //----------------------------------------------------------------------- + // next() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_next() { + assertNotNull(Adjusters.next(MONDAY)); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void factory_next_nullDayOfWeek() { + Adjusters.next(null); + } + + @Test(groups={"tck"}) + public void test_next() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + + for (DayOfWeek dow : DayOfWeek.values()) { + LocalDate test = (LocalDate) Adjusters.next(dow).adjustInto(date); + + assertSame(test.getDayOfWeek(), dow, date + " " + test); + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + assertTrue(dayDiff > 0 && dayDiff < 8); + } else { + assertSame(month, Month.DECEMBER); + assertTrue(date.getDayOfMonth() > 24); + assertEquals(test.getYear(), 2008); + assertSame(test.getMonth(), Month.JANUARY); + assertTrue(test.getDayOfMonth() < 8); + } + } + } + } + } + + //----------------------------------------------------------------------- + // nextOrSame() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_nextOrCurrent() { + assertNotNull(Adjusters.nextOrSame(MONDAY)); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void factory_nextOrCurrent_nullDayOfWeek() { + Adjusters.nextOrSame(null); + } + + @Test(groups={"tck"}) + public void test_nextOrCurrent() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + + for (DayOfWeek dow : DayOfWeek.values()) { + LocalDate test = (LocalDate) Adjusters.nextOrSame(dow).adjustInto(date); + + assertSame(test.getDayOfWeek(), dow); + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + assertTrue(dayDiff < 8); + assertEquals(date.equals(test), date.getDayOfWeek() == dow); + } else { + assertFalse(date.getDayOfWeek() == dow); + assertSame(month, Month.DECEMBER); + assertTrue(date.getDayOfMonth() > 24); + assertEquals(test.getYear(), 2008); + assertSame(test.getMonth(), Month.JANUARY); + assertTrue(test.getDayOfMonth() < 8); + } + } + } + } + } + + //----------------------------------------------------------------------- + // previous() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_previous() { + assertNotNull(Adjusters.previous(MONDAY)); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void factory_previous_nullDayOfWeek() { + Adjusters.previous(null); + } + + @Test(groups={"tck"}) + public void test_previous() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + + for (DayOfWeek dow : DayOfWeek.values()) { + LocalDate test = (LocalDate) Adjusters.previous(dow).adjustInto(date); + + assertSame(test.getDayOfWeek(), dow, date + " " + test); + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + assertTrue(dayDiff < 0 && dayDiff > -8, dayDiff + " " + test); + } else { + assertSame(month, Month.JANUARY); + assertTrue(date.getDayOfMonth() < 8); + assertEquals(test.getYear(), 2006); + assertSame(test.getMonth(), Month.DECEMBER); + assertTrue(test.getDayOfMonth() > 24); + } + } + } + } + } + + //----------------------------------------------------------------------- + // previousOrSame() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_previousOrCurrent() { + assertNotNull(Adjusters.previousOrSame(MONDAY)); + } + + @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) + public void factory_previousOrCurrent_nullDayOfWeek() { + Adjusters.previousOrSame(null); + } + + @Test(groups={"tck"}) + public void test_previousOrCurrent() { + for (Month month : Month.values()) { + for (int i = 1; i <= month.length(false); i++) { + LocalDate date = date(2007, month, i); + + for (DayOfWeek dow : DayOfWeek.values()) { + LocalDate test = (LocalDate) Adjusters.previousOrSame(dow).adjustInto(date); + + assertSame(test.getDayOfWeek(), dow); + + if (test.getYear() == 2007) { + int dayDiff = test.getDayOfYear() - date.getDayOfYear(); + assertTrue(dayDiff <= 0 && dayDiff > -7); + assertEquals(date.equals(test), date.getDayOfWeek() == dow); + } else { + assertFalse(date.getDayOfWeek() == dow); + assertSame(month, Month.JANUARY); + assertTrue(date.getDayOfMonth() < 7); + assertEquals(test.getYear(), 2006); + assertSame(test.getMonth(), Month.DECEMBER); + assertTrue(test.getDayOfMonth() > 25); + } + } + } + } + } + + private LocalDate date(int year, Month month, int day) { + return LocalDate.of(year, month, day); + } + + private LocalDate date(int year, int month, int day) { + return LocalDate.of(year, month, day); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java new file mode 100644 index 00000000000..c3acbdb6f82 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java @@ -0,0 +1,233 @@ +/* + * 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.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; +import static java.time.DayOfWeek.SUNDAY; +import static java.time.DayOfWeek.THURSDAY; +import static java.time.DayOfWeek.TUESDAY; +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 org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test(groups={"tck"}) +public class TCKISOFields { + + @DataProvider(name="quarter") + Object[][] data_quarter() { + return new Object[][] { + {LocalDate.of(1969, 12, 29), 90, 4}, + {LocalDate.of(1969, 12, 30), 91, 4}, + {LocalDate.of(1969, 12, 31), 92, 4}, + + {LocalDate.of(1970, 1, 1), 1, 1}, + {LocalDate.of(1970, 1, 2), 2, 1}, + {LocalDate.of(1970, 2, 28), 59, 1}, + {LocalDate.of(1970, 3, 1), 60, 1}, + {LocalDate.of(1970, 3, 31), 90, 1}, + + {LocalDate.of(1970, 4, 1), 1, 2}, + {LocalDate.of(1970, 6, 30), 91, 2}, + + {LocalDate.of(1970, 7, 1), 1, 3}, + {LocalDate.of(1970, 9, 30), 92, 3}, + + {LocalDate.of(1970, 10, 1), 1, 4}, + {LocalDate.of(1970, 12, 31), 92, 4}, + + {LocalDate.of(1972, 2, 28), 59, 1}, + {LocalDate.of(1972, 2, 29), 60, 1}, + {LocalDate.of(1972, 3, 1), 61, 1}, + {LocalDate.of(1972, 3, 31), 91, 1}, + }; + } + + //----------------------------------------------------------------------- + // DAY_OF_QUARTER + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + // QUARTER_OF_YEAR + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + // builder + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="week") + Object[][] data_week() { + return new Object[][] { + {LocalDate.of(1969, 12, 29), MONDAY, 1, 1970}, + {LocalDate.of(2012, 12, 23), SUNDAY, 51, 2012}, + {LocalDate.of(2012, 12, 24), MONDAY, 52, 2012}, + {LocalDate.of(2012, 12, 27), THURSDAY, 52, 2012}, + {LocalDate.of(2012, 12, 28), FRIDAY, 52, 2012}, + {LocalDate.of(2012, 12, 29), SATURDAY, 52, 2012}, + {LocalDate.of(2012, 12, 30), SUNDAY, 52, 2012}, + {LocalDate.of(2012, 12, 31), MONDAY, 1, 2013}, + {LocalDate.of(2013, 1, 1), TUESDAY, 1, 2013}, + {LocalDate.of(2013, 1, 2), WEDNESDAY, 1, 2013}, + {LocalDate.of(2013, 1, 6), SUNDAY, 1, 2013}, + {LocalDate.of(2013, 1, 7), MONDAY, 2, 2013}, + }; + } + + //----------------------------------------------------------------------- + // WEEK_OF_WEEK_BASED_YEAR + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + // WEEK_BASED_YEAR + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + // builder + //----------------------------------------------------------------------- + @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_loop() { + // loop round at least one 400 year cycle, including before 1970 + LocalDate date = LocalDate.of(1960, 1, 5); // Tuseday of week 1 1960 + int year = 1960; + int wby = 1960; + int weekLen = 52; + int week = 1; + while (date.getYear() < 2400) { + DayOfWeek loopDow = date.getDayOfWeek(); + if (date.getYear() != year) { + year = date.getYear(); + } + if (loopDow == MONDAY) { + week++; + if ((week == 53 && weekLen == 52) || week == 54) { + week = 1; + LocalDate firstDayOfWeekBasedYear = date.plusDays(14).withDayOfYear(1); + DayOfWeek firstDay = firstDayOfWeekBasedYear.getDayOfWeek(); + weekLen = (firstDay == THURSDAY || (firstDay == WEDNESDAY && firstDayOfWeekBasedYear.isLeapYear()) ? 53 : 52); + 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()); + date = date.plusDays(1); + } + } + + // TODO: more tests +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java new file mode 100644 index 00000000000..81e8109c329 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java @@ -0,0 +1,168 @@ +/* + * 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 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.temporal.*; + + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKJulianFields { + + 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() { + return new Object[][] { + {JulianFields.JULIAN_DAY}, + {JulianFields.MODIFIED_JULIAN_DAY}, + {JulianFields.RATA_DIE}, + }; + } + + @DataProvider(name="samples") + Object[][] data_samples() { + return new Object[][] { + {ChronoField.EPOCH_DAY, JAN01_1970, 0L}, + {JulianFields.JULIAN_DAY, JAN01_1970, 2400001L + 40587L}, + {JulianFields.MODIFIED_JULIAN_DAY, JAN01_1970, 40587L}, + {JulianFields.RATA_DIE, JAN01_1970, 710347L + (40587L - 31771L)}, + + {ChronoField.EPOCH_DAY, DEC31_1969, -1L}, + {JulianFields.JULIAN_DAY, DEC31_1969, 2400001L + 40586L}, + {JulianFields.MODIFIED_JULIAN_DAY, DEC31_1969, 40586L}, + {JulianFields.RATA_DIE, DEC31_1969, 710347L + (40586L - 31771L)}, + + {ChronoField.EPOCH_DAY, NOV12_1945, (-24 * 365 - 6) - 31 - 30 + 11}, + {JulianFields.JULIAN_DAY, NOV12_1945, 2431772L}, + {JulianFields.MODIFIED_JULIAN_DAY, NOV12_1945, 31771L}, + {JulianFields.RATA_DIE, NOV12_1945, 710347L}, + + {ChronoField.EPOCH_DAY, JAN01_0001, (-24 * 365 - 6) - 31 - 30 + 11 - 710346L}, + {JulianFields.JULIAN_DAY, JAN01_0001, 2431772L - 710346L}, + {JulianFields.MODIFIED_JULIAN_DAY, JAN01_0001, 31771L - 710346L}, + {JulianFields.RATA_DIE, JAN01_0001, 1}, + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_samples_get(TemporalField field, LocalDate date, long expected) { + assertEquals(date.getLong(field), expected); + } + + @Test(dataProvider="samples", groups={"tck"}) + 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); + } + + //----------------------------------------------------------------------- + // 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 + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java b/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java new file mode 100644 index 00000000000..774777cab03 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java @@ -0,0 +1,756 @@ +/* + * 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.ChronoField.DAY_OF_MONTH; +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.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; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +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.JulianFields; +import java.time.temporal.MonthDay; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.YearMonth; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractDateTimeTest; + +/** + * Test MonthDay. + */ +@Test +public class TCKMonthDay extends AbstractDateTimeTest { + + private MonthDay TEST_07_15; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_07_15 = MonthDay.of(7, 15); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_07_15, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + DAY_OF_MONTH, + MONTH_OF_YEAR, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws ClassNotFoundException, IOException { + assertSerializable(TEST_07_15); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(6); + dos.writeByte(9); + dos.writeByte(16); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(MonthDay.of(9, 16), bytes); + } + + //----------------------------------------------------------------------- + void check(MonthDay test, int m, int d) { + assertEquals(test.getMonth().getValue(), m); + assertEquals(test.getDayOfMonth(), d); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + MonthDay expected = MonthDay.now(Clock.systemDefaultZone()); + MonthDay test = MonthDay.now(); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = MonthDay.now(Clock.systemDefaultZone()); + test = MonthDay.now(); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + MonthDay.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + MonthDay expected = MonthDay.now(Clock.system(zone)); + MonthDay test = MonthDay.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = MonthDay.now(Clock.system(zone)); + test = MonthDay.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock() { + Instant instant = LocalDateTime.of(2010, 12, 31, 0, 0).toInstant(ZoneOffset.UTC); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + MonthDay test = MonthDay.now(clock); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + MonthDay.now((Clock) null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_intMonth() { + assertEquals(TEST_07_15, MonthDay.of(Month.JULY, 15)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_intMonth_dayTooLow() { + MonthDay.of(Month.JANUARY, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_intMonth_dayTooHigh() { + MonthDay.of(Month.JANUARY, 32); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_intMonth_nullMonth() { + MonthDay.of(null, 15); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ints() { + check(TEST_07_15, 7, 15); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_dayTooLow() { + MonthDay.of(1, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_dayTooHigh() { + MonthDay.of(1, 32); + } + + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_monthTooLow() { + MonthDay.of(0, 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_monthTooHigh() { + MonthDay.of(13, 1); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(MonthDay.from(LocalDate.of(2007, 7, 15)), TEST_07_15); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + MonthDay.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + MonthDay.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @DataProvider(name="goodParseData") + Object[][] provider_goodParseData() { + return new Object[][] { + {"--01-01", MonthDay.of(1, 1)}, + {"--01-31", MonthDay.of(1, 31)}, + {"--02-01", MonthDay.of(2, 1)}, + {"--02-29", MonthDay.of(2, 29)}, + {"--03-01", MonthDay.of(3, 1)}, + {"--03-31", MonthDay.of(3, 31)}, + {"--04-01", MonthDay.of(4, 1)}, + {"--04-30", MonthDay.of(4, 30)}, + {"--05-01", MonthDay.of(5, 1)}, + {"--05-31", MonthDay.of(5, 31)}, + {"--06-01", MonthDay.of(6, 1)}, + {"--06-30", MonthDay.of(6, 30)}, + {"--07-01", MonthDay.of(7, 1)}, + {"--07-31", MonthDay.of(7, 31)}, + {"--08-01", MonthDay.of(8, 1)}, + {"--08-31", MonthDay.of(8, 31)}, + {"--09-01", MonthDay.of(9, 1)}, + {"--09-30", MonthDay.of(9, 30)}, + {"--10-01", MonthDay.of(10, 1)}, + {"--10-31", MonthDay.of(10, 31)}, + {"--11-01", MonthDay.of(11, 1)}, + {"--11-30", MonthDay.of(11, 30)}, + {"--12-01", MonthDay.of(12, 1)}, + {"--12-31", MonthDay.of(12, 31)}, + }; + } + + @Test(dataProvider="goodParseData", groups={"tck"}) + public void factory_parse_success(String text, MonthDay expected) { + MonthDay monthDay = MonthDay.parse(text); + assertEquals(monthDay, expected); + } + + //----------------------------------------------------------------------- + @DataProvider(name="badParseData") + Object[][] provider_badParseData() { + return new Object[][] { + {"", 0}, + {"-00", 0}, + {"--FEB-23", 2}, + {"--01-0", 5}, + {"--01-3A", 5}, + }; + } + + @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_fail(String text, int pos) { + try { + MonthDay.parse(text); + fail(String.format("Parse should have failed for %s at position %d", text, pos)); + } + catch (DateTimeParseException ex) { + assertEquals(ex.getParsedString(), text); + assertEquals(ex.getErrorIndex(), pos); + throw ex; + } + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue_Day() { + MonthDay.parse("--06-32"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_invalidValue_Day() { + MonthDay.parse("--06-31"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue_Month() { + MonthDay.parse("--13-25"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + MonthDay.parse(null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + MonthDay.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + MonthDay.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(TEST_07_15.get(ChronoField.DAY_OF_MONTH), 15); + assertEquals(TEST_07_15.get(ChronoField.MONTH_OF_YEAR), 7); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(TEST_07_15.getLong(ChronoField.DAY_OF_MONTH), 15); + assertEquals(TEST_07_15.getLong(ChronoField.MONTH_OF_YEAR), 7); + } + + //----------------------------------------------------------------------- + // get*() + //----------------------------------------------------------------------- + @DataProvider(name="sampleDates") + Object[][] provider_sampleDates() { + return new Object[][] { + {1, 1}, + {1, 31}, + {2, 1}, + {2, 28}, + {2, 29}, + {7, 4}, + {7, 5}, + }; + } + + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_get(int m, int d) { + MonthDay a = MonthDay.of(m, d); + assertEquals(a.getMonth(), Month.of(m)); + assertEquals(a.getDayOfMonth(), d); + } + + //----------------------------------------------------------------------- + // with(Month) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_Month() { + assertEquals(MonthDay.of(6, 30).with(Month.JANUARY), MonthDay.of(1, 30)); + } + + @Test(groups={"tck"}) + public void test_with_Month_adjustToValid() { + assertEquals(MonthDay.of(7, 31).with(Month.JUNE), MonthDay.of(6, 30)); + } + + @Test(groups={"tck"}) + public void test_with_Month_adjustToValidFeb() { + assertEquals(MonthDay.of(7, 31).with(Month.FEBRUARY), MonthDay.of(2, 29)); + } + + @Test(groups={"tck"}) + public void test_with_Month_noChangeEqual() { + MonthDay test = MonthDay.of(6, 30); + assertEquals(test.with(Month.JUNE), test); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_Month_null() { + MonthDay.of(6, 30).with((Month) null); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth() { + assertEquals(MonthDay.of(6, 30).withMonth(1), MonthDay.of(1, 30)); + } + + @Test(groups={"tck"}) + public void test_withMonth_adjustToValid() { + assertEquals(MonthDay.of(7, 31).withMonth(6), MonthDay.of(6, 30)); + } + + @Test(groups={"tck"}) + public void test_withMonth_adjustToValidFeb() { + assertEquals(MonthDay.of(7, 31).withMonth(2), MonthDay.of(2, 29)); + } + + @Test(groups={"tck"}) + public void test_withMonth_int_noChangeEqual() { + MonthDay test = MonthDay.of(6, 30); + assertEquals(test.withMonth(6), test); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooLow() { + MonthDay.of(6, 30).withMonth(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooHigh() { + MonthDay.of(6, 30).withMonth(13); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfMonth() { + assertEquals(MonthDay.of(6, 30).withDayOfMonth(1), MonthDay.of(6, 1)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_invalid() { + MonthDay.of(6, 30).withDayOfMonth(31); + } + + @Test(groups={"tck"}) + public void test_withDayOfMonth_adjustToValidFeb() { + assertEquals(MonthDay.of(2, 1).withDayOfMonth(29), MonthDay.of(2, 29)); + } + + @Test(groups={"tck"}) + public void test_withDayOfMonth_noChangeEqual() { + MonthDay test = MonthDay.of(6, 30); + assertEquals(test.withDayOfMonth(30), test); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_tooLow() { + MonthDay.of(6, 30).withDayOfMonth(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfMonth_tooHigh() { + MonthDay.of(6, 30).withDayOfMonth(32); + } + + //----------------------------------------------------------------------- + // adjustInto() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjustDate() { + MonthDay test = MonthDay.of(6, 30); + LocalDate date = LocalDate.of(2007, 1, 1); + assertEquals(test.adjustInto(date), LocalDate.of(2007, 6, 30)); + } + + @Test(groups={"tck"}) + public void test_adjustDate_resolve() { + MonthDay test = MonthDay.of(2, 29); + LocalDate date = LocalDate.of(2007, 6, 30); + assertEquals(test.adjustInto(date), LocalDate.of(2007, 2, 28)); + } + + @Test(groups={"tck"}) + public void test_adjustDate_equal() { + MonthDay test = MonthDay.of(6, 30); + LocalDate date = LocalDate.of(2007, 6, 30); + assertEquals(test.adjustInto(date), date); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_adjustDate_null() { + TEST_07_15.adjustInto((LocalDate) null); + } + + //----------------------------------------------------------------------- + // isValidYear(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isValidYear_june() { + MonthDay test = MonthDay.of(6, 30); + assertEquals(test.isValidYear(2007), true); + } + + @Test(groups={"tck"}) + public void test_isValidYear_febNonLeap() { + MonthDay test = MonthDay.of(2, 29); + assertEquals(test.isValidYear(2007), false); + } + + @Test(groups={"tck"}) + public void test_isValidYear_febLeap() { + MonthDay test = MonthDay.of(2, 29); + assertEquals(test.isValidYear(2008), true); + } + + //----------------------------------------------------------------------- + // atYear(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atYear_int() { + MonthDay test = MonthDay.of(6, 30); + assertEquals(test.atYear(2008), LocalDate.of(2008, 6, 30)); + } + + @Test(groups={"tck"}) + public void test_atYear_int_leapYearAdjust() { + MonthDay test = MonthDay.of(2, 29); + assertEquals(test.atYear(2005), LocalDate.of(2005, 2, 28)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atYear_int_invalidYear() { + MonthDay test = MonthDay.of(6, 30); + test.atYear(Integer.MIN_VALUE); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + doTest_comparisons_MonthDay( + MonthDay.of(1, 1), + MonthDay.of(1, 31), + MonthDay.of(2, 1), + MonthDay.of(2, 29), + MonthDay.of(3, 1), + MonthDay.of(12, 31) + ); + } + + void doTest_comparisons_MonthDay(MonthDay... localDates) { + for (int i = 0; i < localDates.length; i++) { + MonthDay a = localDates[i]; + for (int j = 0; j < localDates.length; j++) { + MonthDay b = localDates[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + TEST_07_15.compareTo(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isBefore_ObjectNull() { + TEST_07_15.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isAfter_ObjectNull() { + TEST_07_15.isAfter(null); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + MonthDay a = MonthDay.of(1, 1); + MonthDay b = MonthDay.of(1, 1); + MonthDay c = MonthDay.of(2, 1); + MonthDay d = MonthDay.of(1, 2); + + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(a.equals(c), false); + assertEquals(a.equals(d), false); + + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + assertEquals(b.equals(c), false); + assertEquals(b.equals(d), false); + + assertEquals(c.equals(a), false); + assertEquals(c.equals(b), false); + assertEquals(c.equals(c), true); + assertEquals(c.equals(d), false); + + assertEquals(d.equals(a), false); + assertEquals(d.equals(b), false); + assertEquals(d.equals(c), false); + assertEquals(d.equals(d), true); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_07_15.equals(TEST_07_15), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_07_15.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_07_15.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_hashCode(int m, int d) { + MonthDay a = MonthDay.of(m, d); + assertEquals(a.hashCode(), a.hashCode()); + MonthDay b = MonthDay.of(m, d); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_hashCode_unique() { + int leapYear = 2008; + Set uniques = new HashSet(366); + for (int i = 1; i <= 12; i++) { + for (int j = 1; j <= 31; j++) { + if (YearMonth.of(leapYear, i).isValidDay(j)) { + assertTrue(uniques.add(MonthDay.of(i, j).hashCode())); + } + } + } + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {7, 5, "--07-05"}, + {12, 31, "--12-31"}, + {1, 2, "--01-02"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int m, int d, String expected) { + MonthDay test = MonthDay.of(m, d); + String str = test.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("M d"); + String t = MonthDay.of(12, 3).toString(f); + assertEquals(t, "12 3"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + MonthDay.of(12, 3).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java new file mode 100644 index 00000000000..77720220d69 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java @@ -0,0 +1,1949 @@ +/* + * 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/TCKOffsetDateTime.java b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java new file mode 100644 index 00000000000..01d72a4a661 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java @@ -0,0 +1,1488 @@ +/* + * 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.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.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +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.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +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.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.testng.Assert.assertEquals; +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; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +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.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 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 OffsetDateTime. + */ +@Test +public class TCKOffsetDateTime extends AbstractDateTimeTest { + + private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza"); + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_MONE = ZoneOffset.ofHours(-1); + private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2); + private OffsetDateTime TEST_2008_6_30_11_30_59_000000500; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2008_6_30_11_30_59_000000500, OffsetDateTime.MIN, OffsetDateTime.MAX}; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + NANO_OF_DAY, + MICRO_OF_SECOND, + MICRO_OF_DAY, + MILLI_OF_SECOND, + MILLI_OF_DAY, + SECOND_OF_MINUTE, + SECOND_OF_DAY, + MINUTE_OF_HOUR, + MINUTE_OF_DAY, + CLOCK_HOUR_OF_AMPM, + HOUR_OF_AMPM, + CLOCK_HOUR_OF_DAY, + HOUR_OF_DAY, + AMPM_OF_DAY, + 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, + INSTANT_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 Exception { + assertSerializable(TEST_2008_6_30_11_30_59_000000500); + assertSerializable(OffsetDateTime.MIN); + assertSerializable(OffsetDateTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(3); + } + byte[] bytes = baos.toByteArray(); + ByteArrayOutputStream baosDateTime = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosDateTime) ) { + dos.writeByte(5); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(464_000_000); + } + byte[] bytesDateTime = baosDateTime.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(); + LocalDateTime ldt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 464_000_000); + assertSerializedBySer(OffsetDateTime.of(ldt, ZoneOffset.ofHours(1)), bytes, bytesDateTime, bytesOffset); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void constant_MIN() { + check(OffsetDateTime.MIN, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0, ZoneOffset.MAX); + } + + @Test + public void constant_MAX() { + check(OffsetDateTime.MAX, Year.MAX_VALUE, 12, 31, 23, 59, 59, 999999999, ZoneOffset.MIN); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + OffsetDateTime expected = OffsetDateTime.now(Clock.systemDefaultZone()); + OffsetDateTime test = OffsetDateTime.now(); + long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().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()); + } + assertTrue(diff < 100000000); // less than 0.1 secs + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_utc() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetDateTime test = OffsetDateTime.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2)); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 123456789); + assertEquals(test.getOffset(), ZoneOffset.UTC); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_offset() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE); + OffsetDateTime test = OffsetDateTime.now(clock); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 123456789); + assertEquals(test.getOffset(), OFFSET_PONE); + } + } + + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay_beforeEpoch() { + LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L); + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetDateTime test = OffsetDateTime.now(clock); + assertEquals(test.getYear(), 1969); + assertEquals(test.getMonth(), Month.DECEMBER); + assertEquals(test.getDayOfMonth(), 31); + expected = expected.minusSeconds(1); + assertEquals(test.getTime(), 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); + for (int i = -9; i < 15; i++) { + ZoneOffset offset = ZoneOffset.ofHours(i); + Clock clock = Clock.fixed(base.toInstant(), offset); + OffsetDateTime test = OffsetDateTime.now(clock); + assertEquals(test.getHour(), (12 + i) % 24); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + assertEquals(test.getOffset(), offset); + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullZoneId() { + OffsetDateTime.now((ZoneId) null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + OffsetDateTime.now((Clock) null); + } + + //----------------------------------------------------------------------- + private void check(OffsetDateTime test, int y, int mo, int d, int h, int m, int s, int n, ZoneOffset offset) { + assertEquals(test.getYear(), y); + assertEquals(test.getMonth().getValue(), mo); + assertEquals(test.getDayOfMonth(), d); + assertEquals(test.getHour(), h); + assertEquals(test.getMinute(), m); + assertEquals(test.getSecond(), s); + assertEquals(test.getNano(), n); + assertEquals(test.getOffset(), offset); + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + assertEquals(OffsetDateTime.of(LocalDateTime.of(y, mo, d, h, m, s, n), offset), test); + } + + //----------------------------------------------------------------------- + // 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); + } + + //----------------------------------------------------------------------- + @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); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_LocalDateLocalTimeZoneOffset() { + LocalDate date = LocalDate.of(2008, 6, 30); + LocalTime time = LocalTime.of(11, 30, 10, 500); + OffsetDateTime test = OffsetDateTime.of(date, time, OFFSET_PONE); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTimeZoneOffset_nullLocalDate() { + LocalTime time = LocalTime.of(11, 30, 10, 500); + OffsetDateTime.of((LocalDate) null, time, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTimeZoneOffset_nullLocalTime() { + LocalDate date = LocalDate.of(2008, 6, 30); + OffsetDateTime.of(date, (LocalTime) null, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTimeZoneOffset_nullOffset() { + LocalDate date = LocalDate.of(2008, 6, 30); + LocalTime time = LocalTime.of(11, 30, 10, 500); + OffsetDateTime.of(date, time, (ZoneOffset) null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_LocalDateTimeZoneOffset() { + LocalDateTime dt = LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500)); + OffsetDateTime test = OffsetDateTime.of(dt, OFFSET_PONE); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateTimeZoneOffset_nullProvider() { + OffsetDateTime.of((LocalDateTime) null, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateTimeZoneOffset_nullOffset() { + LocalDateTime dt = LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500)); + OffsetDateTime.of(dt, (ZoneOffset) null); + } + + //----------------------------------------------------------------------- + // from() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(OffsetDateTime.from( + OffsetDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(17, 30), OFFSET_PONE)), + OffsetDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(17, 30), OFFSET_PONE)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + OffsetDateTime.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_Calendricals_null() { + OffsetDateTime.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_parse(int y, int month, int d, int h, int m, int s, int n, String offsetId, String text) { + OffsetDateTime t = OffsetDateTime.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.getOffset().getId(), offsetId); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue() { + OffsetDateTime.parse("2008-06-32T11:15+01:00"); + } + + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_invalidValue() { + OffsetDateTime.parse("2008-06-31T11:15+01:00"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + OffsetDateTime.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + OffsetDateTime.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + OffsetDateTime.parse("ANY", null); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void constructor_nullTime() throws Throwable { + Constructor con = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.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 = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.class, ZoneOffset.class); + con.setAccessible(true); + try { + con.newInstance(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), null); + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {2008, 6, 30, 11, 30, 20, 500, OFFSET_PONE}, + {2008, 6, 30, 11, 0, 0, 0, OFFSET_PONE}, + {2008, 6, 30, 23, 59, 59, 999999999, OFFSET_PONE}, + {-1, 1, 1, 0, 0, 0, 0, OFFSET_PONE}, + }; + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_get(int y, int o, int d, int h, int m, int s, int n, ZoneOffset offset) { + LocalDate localDate = LocalDate.of(y, o, d); + LocalTime localTime = LocalTime.of(h, m, s, n); + LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); + OffsetDateTime a = OffsetDateTime.of(localDateTime, offset); + + 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()); + + assertEquals(a.getHour(), localDateTime.getHour()); + assertEquals(a.getMinute(), localDateTime.getMinute()); + 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()); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 40, 987654321), 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.HOUR_OF_DAY), 12); + assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600); + } + + @Test + public void test_getLong_TemporalField() { + OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 40, 987654321), 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.HOUR_OF_DAY), 12); + assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30); + assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40); + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), test.toEpochSecond()); + assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_2008_6_30_11_30_59_000000500.query(null); + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_adjustment() { + final OffsetDateTime sample = OffsetDateTime.of(LocalDate.of(2012, 3, 4), LocalTime.of(23, 5), OFFSET_PONE); + TemporalAdjuster adjuster = new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return sample; + } + }; + assertEquals(TEST_2008_6_30_11_30_59_000000500.with(adjuster), sample); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_LocalDate() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalDate.of(2012, 9, 3)); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(11, 30, 59, 500), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_LocalTime() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalTime.of(19, 15)); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(19, 15), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_LocalDateTime() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15))); + 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)); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(19, 15), OFFSET_PTWO)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_OffsetDateTime() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PTWO)); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PTWO)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_Month() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(DECEMBER); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 12, 30),LocalTime.of(11, 30, 59, 500), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_ZoneOffset() { + OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OFFSET_PTWO); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PTWO)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_adjustment_null() { + TEST_2008_6_30_11_30_59_000000500.with((TemporalAdjuster) null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_withOffsetSameLocal_null() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + base.withOffsetSameLocal(null); + } + + //----------------------------------------------------------------------- + // withOffsetSameInstant() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withOffsetSameInstant() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withOffsetSameInstant(OFFSET_PTWO); + OffsetDateTime expected = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 59), OFFSET_PTWO); + assertEquals(test, expected); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_withOffsetSameInstant_null() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + base.withOffsetSameInstant(null); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withYear(2007); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withMonth(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 1, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withDayOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfMonth_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withDayOfMonth(15); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 15), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withDayOfYear(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withDayOfYear_normal() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.withDayOfYear(33); + assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 2, 2), LocalTime.of(11, 30, 59, 500), OFFSET_PONE)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_illegal() { + TEST_2008_6_30_11_30_59_000000500.withDayOfYear(367); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withDayOfYear_invalid() { + OffsetDateTime.of(LocalDate.of(2007, 2, 2), LocalTime.of(11, 30), OFFSET_PONE).withDayOfYear(366); + } + + //----------------------------------------------------------------------- + // withHour() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withHour_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withHour(15); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(15, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withMinute() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMinute_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withMinute(15); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 15, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withSecond_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withSecond(15); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 15), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // withNano() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withNanoOfSecond_normal() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE); + OffsetDateTime test = base.withNano(15); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 15), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // truncatedTo(TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_truncatedTo_normal() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(NANOS), TEST_2008_6_30_11_30_59_000000500); + assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(SECONDS), TEST_2008_6_30_11_30_59_000000500.withNano(0)); + assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(DAYS), TEST_2008_6_30_11_30_59_000000500.with(LocalTime.MIDNIGHT)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_2008_6_30_11_30_59_000000500.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus(Period) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + //----------------------------------------------------------------------- + // plus(Duration) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + @Test(groups={"tck"}) + public void test_plus_Duration_zero() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(Duration.ZERO); + assertEquals(t, TEST_2008_6_30_11_30_59_000000500); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_Duration_null() { + TEST_2008_6_30_11_30_59_000000500.plus((Duration) null); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusYears(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2009, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMonths() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusMonths(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusWeeks() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusWeeks() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusWeeks(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 7), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusDays() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusDays(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusHours() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusHours(13); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(0, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMinutes() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusMinutes(30); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 0, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusSeconds() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusSeconds(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 31, 0), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // plusNanos() + //----------------------------------------------------------------------- + @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 test = base.plusNanos(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minus(Period) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + //----------------------------------------------------------------------- + // minus(Duration) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + @Test(groups={"tck"}) + public void test_minus_Duration_zero() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(Duration.ZERO); + assertEquals(t, TEST_2008_6_30_11_30_59_000000500); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_Duration_null() { + TEST_2008_6_30_11_30_59_000000500.minus((Duration) null); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusYears(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMonths() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusMonths(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 5, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusWeeks() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusWeeks() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusWeeks(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 23), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusDays() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusDays() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusDays(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(11, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusHours() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusHours(13); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(22, 30, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMinutes() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusMinutes(30); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0, 59), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusSeconds() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusSeconds(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // minusNanos() + //----------------------------------------------------------------------- + @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 test = base.minusNanos(1); + assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58, 999999999), OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // atZoneSameInstant() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atZone() { + OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO); + assertEquals(t.atZoneSameInstant(ZONE_PARIS), + ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(15, 30)), 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); + t.atZoneSameInstant((ZoneId) null); + } + + //----------------------------------------------------------------------- + // atZoneSimilarLocal() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atZoneSimilarLocal() { + OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO); + assertEquals(t.atZoneSimilarLocal(ZONE_PARIS), + ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), 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); + assertEquals(t.atZoneSimilarLocal(ZONE_GAZA), + ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 4, 1), LocalTime.of(1, 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()); + 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()); + 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); + t.atZoneSimilarLocal((ZoneId) null); + } + + //----------------------------------------------------------------------- + // toEpochSecond() + //----------------------------------------------------------------------- + @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); + assertEquals(a.toEpochSecond(), i); + } + } + + @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); + assertEquals(a.toEpochSecond(), -i); + } + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) < 0, true); + } + + @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 + 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.toInstant().compareTo(b.toInstant()) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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 + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + } + + @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); + a.compareTo(null); + } + + @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonOffsetDateTime() { + Comparable c = TEST_2008_6_30_11_30_59_000000500; + c.compareTo(new Object()); + } + + //----------------------------------------------------------------------- + // isAfter() / isBefore() / isEqual() + //----------------------------------------------------------------------- + @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 + 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() { + 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 + 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() { + 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 + 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() { + OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), 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); + 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); + a.isAfter(null); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @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); + 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); + 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); + 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); + 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); + 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); + 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); + assertEquals(a.equals(b), false); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.equals(TEST_2008_6_30_11_30_59_000000500), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.equals(null), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {2008, 6, 30, 11, 30, 59, 0, "Z", "2008-06-30T11:30:59Z"}, + {2008, 6, 30, 11, 30, 59, 0, "+01:00", "2008-06-30T11:30:59+01:00"}, + {2008, 6, 30, 11, 30, 59, 999000000, "Z", "2008-06-30T11:30:59.999Z"}, + {2008, 6, 30, 11, 30, 59, 999000000, "+01:00", "2008-06-30T11:30:59.999+01:00"}, + {2008, 6, 30, 11, 30, 59, 999000, "Z", "2008-06-30T11:30:59.000999Z"}, + {2008, 6, 30, 11, 30, 59, 999000, "+01:00", "2008-06-30T11:30:59.000999+01:00"}, + {2008, 6, 30, 11, 30, 59, 999, "Z", "2008-06-30T11:30:59.000000999Z"}, + {2008, 6, 30, 11, 30, 59, 999, "+01:00", "2008-06-30T11:30:59.000000999+01:00"}, + }; + } + + @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)); + String str = t.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @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); + 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); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java new file mode 100644 index 00000000000..374268589ad --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java @@ -0,0 +1,1325 @@ +/* + * 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.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +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.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.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalSubtractor; + +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 OffsetTime. + */ +@Test +public class TCKOffsetTime extends AbstractDateTimeTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final LocalDate DATE = LocalDate.of(2008, 12, 3); + private OffsetTime TEST_11_30_59_500_PONE; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_11_30_59_500_PONE = OffsetTime.of(LocalTime.of(11, 30, 59, 500), OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_11_30_59_500_PONE, OffsetTime.MIN, OffsetTime.MAX}; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + NANO_OF_SECOND, + NANO_OF_DAY, + MICRO_OF_SECOND, + MICRO_OF_DAY, + MILLI_OF_SECOND, + MILLI_OF_DAY, + SECOND_OF_MINUTE, + SECOND_OF_DAY, + MINUTE_OF_HOUR, + MINUTE_OF_DAY, + CLOCK_HOUR_OF_AMPM, + HOUR_OF_AMPM, + CLOCK_HOUR_OF_DAY, + HOUR_OF_DAY, + AMPM_OF_DAY, + OFFSET_SECONDS, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_11_30_59_500_PONE); + assertSerializable(OffsetTime.MIN); + assertSerializable(OffsetTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(2); + } + byte[] bytes = baos.toByteArray(); + ByteArrayOutputStream baosTime = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosTime) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(464_000_000); + } + byte[] bytesTime = baosTime.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(OffsetTime.of(LocalTime.of(22, 17, 59, 464_000_000), ZoneOffset.ofHours(1)), bytes, + bytesTime, bytesOffset); + } + + //----------------------------------------------------------------------- + // constants + //----------------------------------------------------------------------- + @Test + public void constant_MIN() { + check(OffsetTime.MIN, 0, 0, 0, 0, ZoneOffset.MAX); + } + + @Test + public void constant_MAX() { + check(OffsetTime.MAX, 23, 59, 59, 999999999, ZoneOffset.MIN); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + ZonedDateTime nowDT = ZonedDateTime.now(); + + OffsetTime expected = OffsetTime.now(Clock.systemDefaultZone()); + OffsetTime test = OffsetTime.now(); + long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + assertTrue(diff < 100000000); // less than 0.1 secs + assertEquals(test.getOffset(), nowDT.getOffset()); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock_allSecsInDay() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i, 8); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetTime test = OffsetTime.now(clock); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 8); + assertEquals(test.getOffset(), ZoneOffset.UTC); + } + } + + @Test(groups={"tck"}) + public void now_Clock_beforeEpoch() { + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i, 8); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + OffsetTime test = OffsetTime.now(clock); + assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24); + assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60); + assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60); + assertEquals(test.getNano(), 8); + assertEquals(test.getOffset(), 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); + OffsetTime test = OffsetTime.now(clock); + assertEquals(test.getHour(), (12 + i) % 24); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + assertEquals(test.getOffset(), offset); + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullZoneId() { + OffsetTime.now((ZoneId) null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + OffsetTime.now((Clock) null); + } + + //----------------------------------------------------------------------- + // 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.getOffset(), offset); + + assertEquals(test.getHour(), h); + assertEquals(test.getMinute(), m); + assertEquals(test.getSecond(), s); + assertEquals(test.getNano(), n); + + assertEquals(test, test); + assertEquals(test.hashCode(), test.hashCode()); + 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); + check(test, 11, 30, 10, 500, OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_LocalTimeZoneOffset() { + LocalTime localTime = LocalTime.of(11, 30, 10, 500); + OffsetTime test = OffsetTime.of(localTime, OFFSET_PONE); + check(test, 11, 30, 10, 500, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_LocalTimeZoneOffset_nullTime() { + OffsetTime.of((LocalTime) null, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_LocalTimeZoneOffset_nullOffset() { + LocalTime localTime = LocalTime.of(11, 30, 10, 500); + OffsetTime.of(localTime, (ZoneOffset) null); + } + + //----------------------------------------------------------------------- + // ofInstant() + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_nullInstant() { + OffsetTime.ofInstant((Instant) null, ZoneOffset.UTC); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_ofInstant_nullOffset() { + Instant instant = Instant.ofEpochSecond(0L); + OffsetTime.ofInstant(instant, (ZoneOffset) null); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_allSecsInDay() { + for (int i = 0; i < (2 * 24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i, 8); + OffsetTime test = OffsetTime.ofInstant(instant, ZoneOffset.UTC); + assertEquals(test.getHour(), (i / (60 * 60)) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + assertEquals(test.getNano(), 8); + } + } + + @Test(groups={"tck"}) + public void factory_ofInstant_beforeEpoch() { + for (int i =-1; i >= -(24 * 60 * 60); i--) { + Instant instant = Instant.ofEpochSecond(i, 8); + OffsetTime test = OffsetTime.ofInstant(instant, ZoneOffset.UTC); + assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24); + assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60); + assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60); + assertEquals(test.getNano(), 8); + } + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ofInstant_maxYear() { + OffsetTime test = OffsetTime.ofInstant(Instant.MAX, ZoneOffset.UTC); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 999_999_999); + } + + @Test(groups={"tck"}) + public void factory_ofInstant_minYear() { + OffsetTime test = OffsetTime.ofInstant(Instant.MIN, ZoneOffset.UTC); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @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)); + } + + @Test(groups={"tck"}) + public void test_from_TemporalAccessor_ZDT() { + ZonedDateTime base = LocalDateTime.of(2007, 7, 15, 11, 30, 59, 500).atZone(OFFSET_PONE); + assertEquals(OffsetTime.from(base), TEST_11_30_59_500_PONE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_invalid_noDerive() { + OffsetTime.from(LocalDate.of(2007, 7, 15)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_from_TemporalAccessor_null() { + OffsetTime.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @Test(dataProvider = "sampleToString", groups={"tck"}) + public void factory_parse_validText(int h, int m, int s, int n, String offsetId, String parsable) { + OffsetTime t = OffsetTime.parse(parsable); + assertNotNull(t, parsable); + check(t, h, m, s, n, ZoneOffset.of(offsetId)); + } + + @DataProvider(name="sampleBadParse") + Object[][] provider_sampleBadParse() { + return new Object[][]{ + {"00;00"}, + {"12-00"}, + {"-01:00"}, + {"00:00:00-09"}, + {"00:00:00,09"}, + {"00:00:abs"}, + {"11"}, + {"11:30"}, + {"11:30+01:00[Europe/Paris]"}, + }; + } + + @Test(dataProvider = "sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_invalidText(String unparsable) { + OffsetTime.parse(unparsable); + } + + //-----------------------------------------------------------------------s + @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_illegalHour() { + OffsetTime.parse("25:00+01:00"); + } + + @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_illegalMinute() { + OffsetTime.parse("12:60+01:00"); + } + + @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"}) + public void factory_parse_illegalSecond() { + OffsetTime.parse("12:12:60+01:00"); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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))); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullText() { + DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + OffsetTime.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + OffsetTime.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // constructor + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void constructor_nullTime() throws Throwable { + Constructor con = OffsetTime.class.getDeclaredConstructor(LocalTime.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 = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class); + con.setAccessible(true); + try { + con.newInstance(LocalTime.of(11, 30), null); + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {11, 30, 20, 500, OFFSET_PONE}, + {11, 0, 0, 0, OFFSET_PONE}, + {23, 59, 59, 999999999, OFFSET_PONE}, + }; + } + + @Test(dataProvider="sampleTimes", groups={"tck"}) + public void test_get(int h, int m, int s, int n, ZoneOffset offset) { + LocalTime localTime = LocalTime.of(h, m, s, n); + OffsetTime a = OffsetTime.of(localTime, offset); + + assertEquals(a.getTime(), localTime); + assertEquals(a.getOffset(), offset); + assertEquals(a.toString(), localTime.toString() + offset.toString()); + assertEquals(a.getHour(), localTime.getHour()); + assertEquals(a.getMinute(), localTime.getMinute()); + assertEquals(a.getSecond(), localTime.getSecond()); + assertEquals(a.getNano(), localTime.getNano()); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + OffsetTime test = OffsetTime.of(LocalTime.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); + assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600); + } + + @Test + public void test_getLong_TemporalField() { + OffsetTime test = OffsetTime.of(LocalTime.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); + assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321); + assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0); + assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1); + + assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600); + } + + //----------------------------------------------------------------------- + // 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); + } + + @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 + 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(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_11_30_59_500_PONE.query(null); + } + + //----------------------------------------------------------------------- + // withOffsetSameLocal() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withOffsetSameLocal() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withOffsetSameLocal(OFFSET_PTWO); + assertEquals(test.getTime(), base.getTime()); + 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 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); + base.withOffsetSameLocal(null); + } + + //----------------------------------------------------------------------- + // withOffsetSameInstant() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withOffsetSameInstant() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withOffsetSameInstant(OFFSET_PTWO); + OffsetTime expected = OffsetTime.of(LocalTime.of(12, 30, 59), 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 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); + base.withOffsetSameInstant(null); + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_adjustment() { + final OffsetTime sample = OffsetTime.of(LocalTime.of(23, 5), OFFSET_PONE); + TemporalAdjuster adjuster = new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return sample; + } + }; + assertEquals(TEST_11_30_59_500_PONE.with(adjuster), sample); + } + + @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)); + } + + @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)); + } + + @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)); + } + + @Test(groups={"tck"}) + public void test_with_adjustment_AmPm() { + OffsetTime test = TEST_11_30_59_500_PONE.with(new TemporalAdjuster() { + @Override + public Temporal adjustInto(Temporal dateTime) { + return dateTime.with(HOUR_OF_DAY, 23); + } + }); + assertEquals(test, OffsetTime.of(LocalTime.of(23, 30, 59, 500), OFFSET_PONE)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_adjustment_null() { + TEST_11_30_59_500_PONE.with((TemporalAdjuster) null); + } + + //----------------------------------------------------------------------- + // with(TemporalField, long) + //----------------------------------------------------------------------- + @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)); + + assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), ZoneOffset.ofHoursMinutesSeconds(2, 0, 5))); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"} ) + public void test_with_TemporalField_null() { + TEST_11_30_59_500_PONE.with((TemporalField) null, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"} ) + public void test_with_TemporalField_invalidField() { + TEST_11_30_59_500_PONE.with(ChronoField.YEAR, 0); + } + + //----------------------------------------------------------------------- + // withHour() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withHour_normal() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withHour(15); + assertEquals(test, OffsetTime.of(LocalTime.of(15, 30, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_withHour_noChange() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withHour(11); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withMinute() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMinute_normal() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withMinute(15); + assertEquals(test, OffsetTime.of(LocalTime.of(11, 15, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_withMinute_noChange() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withMinute(30); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withSecond() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withSecond_normal() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withSecond(15); + assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 15), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_withSecond_noChange() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.withSecond(59); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // withNano() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withNanoOfSecond_normal() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE); + OffsetTime test = base.withNano(15); + assertEquals(test, OffsetTime.of(LocalTime.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 test = base.withNano(1); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // truncatedTo(TemporalUnit) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_truncatedTo_normal() { + assertEquals(TEST_11_30_59_500_PONE.truncatedTo(NANOS), TEST_11_30_59_500_PONE); + assertEquals(TEST_11_30_59_500_PONE.truncatedTo(SECONDS), TEST_11_30_59_500_PONE.withNano(0)); + assertEquals(TEST_11_30_59_500_PONE.truncatedTo(DAYS), TEST_11_30_59_500_PONE.with(LocalTime.MIDNIGHT)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_11_30_59_500_PONE.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus(PlusAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + @Test(groups={"tck"}) + public void test_plus_PlusAdjuster_noChange() { + OffsetTime t = TEST_11_30_59_500_PONE.plus(MockSimplePeriod.of(0, SECONDS)); + assertEquals(t, TEST_11_30_59_500_PONE); + } + + @Test(groups={"tck"}) + public void test_plus_PlusAdjuster_zero() { + OffsetTime t = TEST_11_30_59_500_PONE.plus(Period.ZERO); + assertEquals(t, TEST_11_30_59_500_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_plus_PlusAdjuster_null() { + TEST_11_30_59_500_PONE.plus((TemporalAdder) null); + } + + //----------------------------------------------------------------------- + // plusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusHours() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusHours(13); + assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_plusHours_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusHours(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMinutes() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusMinutes(30); + assertEquals(test, OffsetTime.of(LocalTime.of(12, 0, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_plusMinutes_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusMinutes(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusSeconds() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusSeconds(1); + assertEquals(test, OffsetTime.of(LocalTime.of(11, 31, 0), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_plusSeconds_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.plusSeconds(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // plusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusNanos() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetTime test = base.plusNanos(1); + assertEquals(test, OffsetTime.of(LocalTime.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 test = base.plusNanos(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minus(MinusAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + 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)); + } + + @Test(groups={"tck"}) + public void test_minus_MinusAdjuster_noChange() { + OffsetTime t = TEST_11_30_59_500_PONE.minus(MockSimplePeriod.of(0, SECONDS)); + assertEquals(t, TEST_11_30_59_500_PONE); + } + + @Test(groups={"tck"}) + public void test_minus_MinusAdjuster_zero() { + OffsetTime t = TEST_11_30_59_500_PONE.minus(Period.ZERO); + assertEquals(t, TEST_11_30_59_500_PONE); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_minus_MinusAdjuster_null() { + TEST_11_30_59_500_PONE.minus((TemporalSubtractor) null); + } + + //----------------------------------------------------------------------- + // minusHours() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusHours() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusHours(-13); + assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_minusHours_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusHours(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusMinutes() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMinutes() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusMinutes(50); + assertEquals(test, OffsetTime.of(LocalTime.of(10, 40, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_minusMinutes_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusMinutes(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusSeconds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusSeconds() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusSeconds(60); + assertEquals(test, OffsetTime.of(LocalTime.of(11, 29, 59), OFFSET_PONE)); + } + + @Test(groups={"tck"}) + public void test_minusSeconds_zero() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime test = base.minusSeconds(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // minusNanos() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusNanos() { + OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetTime test = base.minusNanos(1); + assertEquals(test, OffsetTime.of(LocalTime.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 test = base.minusNanos(0); + assertEquals(test, base); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @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 + 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(convertInstant(a).compareTo(convertInstant(b)) < 0, true); + } + + @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 + 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(convertInstant(a).compareTo(convertInstant(b)) < 0, true); + } + + @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 + 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(convertInstant(a).compareTo(convertInstant(b)) < 0, true); + } + + @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 + 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(convertInstant(a).compareTo(convertInstant(b)) < 0, true); + } + + @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 + 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(convertInstant(a).compareTo(convertInstant(b)) == 0, true); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_null() { + OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + a.compareTo(null); + } + + @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compareToNonOffsetTime() { + Comparable c = TEST_11_30_59_500_PONE; + c.compareTo(new Object()); + } + + private Instant convertInstant(OffsetTime ot) { + return DATE.atTime(ot.getTime()).toInstant(ot.getOffset()); + } + + //----------------------------------------------------------------------- + // isAfter() / isBefore() / isEqual() + //----------------------------------------------------------------------- + @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 + 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_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 + 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() { + 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 + 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_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 + 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() { + 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 + 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() { + OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), 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); + 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); + a.isEqual(null); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @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); + 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); + 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); + 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); + 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); + 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); + assertEquals(a.equals(b), false); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_11_30_59_500_PONE.equals(TEST_11_30_59_500_PONE), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_11_30_59_500_PONE.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_11_30_59_500_PONE.equals(null), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {11, 30, 59, 0, "Z", "11:30:59Z"}, + {11, 30, 59, 0, "+01:00", "11:30:59+01:00"}, + {11, 30, 59, 999000000, "Z", "11:30:59.999Z"}, + {11, 30, 59, 999000000, "+01:00", "11:30:59.999+01:00"}, + {11, 30, 59, 999000, "Z", "11:30:59.000999Z"}, + {11, 30, 59, 999000, "+01:00", "11:30:59.000999+01:00"}, + {11, 30, 59, 999, "Z", "11:30:59.000000999Z"}, + {11, 30, 59, 999, "+01:00", "11:30:59.000000999+01:00"}, + }; + } + + @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)); + String str = t.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @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); + 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); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java b/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java new file mode 100644 index 00000000000..d67e6aae297 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java @@ -0,0 +1,286 @@ +/* + * 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 new file mode 100644 index 00000000000..9119a70fa65 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java @@ -0,0 +1,365 @@ +/* + * 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.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_YEAR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; + +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.temporal.TemporalField; +import java.time.format.DateTimeBuilder; +import java.time.temporal.ValueRange; +import java.time.temporal.WeekFields; + +import org.testng.annotations.Test; + +/** + * Test WeekFields. + */ +@Test +public class TCKWeekFields { + + @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(groups={"tck"}) + public void test_DayOfWeek() { + 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); + + 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); + + 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); + + // 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); + + 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); + + // 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(); + + 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); + + 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); + + 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"); + } + } + } + } + + @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); + + 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)); + + 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); + } + } + } + } + + @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); + + 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 + } + } + } +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKYear.java b/jdk/test/java/time/tck/java/time/temporal/TCKYear.java new file mode 100644 index 00000000000..5464c6b4241 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKYear.java @@ -0,0 +1,781 @@ +/* + * 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.ChronoField.ERA; +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.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.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.JulianFields; +import java.time.temporal.MonthDay; +import java.time.temporal.OffsetDateTime; +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 org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractDateTimeTest; + +/** + * Test Year. + */ +@Test +public class TCKYear extends AbstractDateTimeTest { + + private static final Year TEST_2008 = Year.of(2008); + + @BeforeMethod + public void setUp() { + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2008, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + YEAR_OF_ERA, + YEAR, + ERA, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Year.of(2)); + assertSerializable(Year.of(0)); + assertSerializable(Year.of(-2)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeInt(2012); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Year.of(2012), bytes); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + Year expected = Year.now(Clock.systemDefaultZone()); + Year test = Year.now(); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = Year.now(Clock.systemDefaultZone()); + test = Year.now(); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + Year.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + Year expected = Year.now(Clock.system(zone)); + Year test = Year.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = Year.now(Clock.system(zone)); + test = Year.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock() { + Instant instant = OffsetDateTime.of(LocalDate.of(2010, 12, 31), LocalTime.of(0, 0), ZoneOffset.UTC).toInstant(); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + Year test = Year.now(clock); + assertEquals(test.getValue(), 2010); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + Year.now((Clock) null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_int_singleton() { + for (int i = -4; i <= 2104; i++) { + Year test = Year.of(i); + assertEquals(test.getValue(), i); + assertEquals(Year.of(i), test); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_tooLow() { + Year.of(Year.MIN_VALUE - 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_int_tooHigh() { + Year.of(Year.MAX_VALUE + 1); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(Year.from(LocalDate.of(2007, 7, 15)), Year.of(2007)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + Year.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + Year.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @DataProvider(name="goodParseData") + Object[][] provider_goodParseData() { + return new Object[][] { + {"0000", Year.of(0)}, + {"9999", Year.of(9999)}, + {"2000", Year.of(2000)}, + + {"+12345678", Year.of(12345678)}, + {"+123456", Year.of(123456)}, + {"-1234", Year.of(-1234)}, + {"-12345678", Year.of(-12345678)}, + + {"+" + Year.MAX_VALUE, Year.of(Year.MAX_VALUE)}, + {"" + Year.MIN_VALUE, Year.of(Year.MIN_VALUE)}, + }; + } + + @Test(dataProvider="goodParseData", groups={"tck"}) + public void factory_parse_success(String text, Year expected) { + Year year = Year.parse(text); + assertEquals(year, expected); + } + + @DataProvider(name="badParseData") + Object[][] provider_badParseData() { + return new Object[][] { + {"", 0}, + {"-00", 1}, + {"--01-0", 1}, + {"A01", 0}, + {"200", 0}, + {"2009/12", 4}, + + {"-0000-10", 0}, + {"-12345678901-10", 11}, + {"+1-10", 1}, + {"+12-10", 1}, + {"+123-10", 1}, + {"+1234-10", 0}, + {"12345-10", 0}, + {"+12345678901-10", 11}, + }; + } + + @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_fail(String text, int pos) { + try { + Year.parse(text); + fail(String.format("Parse should have failed for %s at position %d", text, pos)); + } catch (DateTimeParseException ex) { + assertEquals(ex.getParsedString(), text); + assertEquals(ex.getErrorIndex(), pos); + throw ex; + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + Year.parse(null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + Year.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + Year.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(TEST_2008.get(ChronoField.YEAR), 2008); + assertEquals(TEST_2008.get(ChronoField.YEAR_OF_ERA), 2008); + assertEquals(TEST_2008.get(ChronoField.ERA), 1); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(TEST_2008.getLong(ChronoField.YEAR), 2008); + assertEquals(TEST_2008.getLong(ChronoField.YEAR_OF_ERA), 2008); + assertEquals(TEST_2008.getLong(ChronoField.ERA), 1); + } + + //----------------------------------------------------------------------- + // isLeap() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isLeap() { + assertEquals(Year.of(1999).isLeap(), false); + assertEquals(Year.of(2000).isLeap(), true); + assertEquals(Year.of(2001).isLeap(), false); + + assertEquals(Year.of(2007).isLeap(), false); + assertEquals(Year.of(2008).isLeap(), true); + assertEquals(Year.of(2009).isLeap(), false); + assertEquals(Year.of(2010).isLeap(), false); + assertEquals(Year.of(2011).isLeap(), false); + assertEquals(Year.of(2012).isLeap(), true); + + assertEquals(Year.of(2095).isLeap(), false); + assertEquals(Year.of(2096).isLeap(), true); + assertEquals(Year.of(2097).isLeap(), false); + assertEquals(Year.of(2098).isLeap(), false); + assertEquals(Year.of(2099).isLeap(), false); + assertEquals(Year.of(2100).isLeap(), false); + assertEquals(Year.of(2101).isLeap(), false); + assertEquals(Year.of(2102).isLeap(), false); + assertEquals(Year.of(2103).isLeap(), false); + assertEquals(Year.of(2104).isLeap(), true); + assertEquals(Year.of(2105).isLeap(), false); + + assertEquals(Year.of(-500).isLeap(), false); + assertEquals(Year.of(-400).isLeap(), true); + assertEquals(Year.of(-300).isLeap(), false); + assertEquals(Year.of(-200).isLeap(), false); + assertEquals(Year.of(-100).isLeap(), false); + assertEquals(Year.of(0).isLeap(), true); + assertEquals(Year.of(100).isLeap(), false); + assertEquals(Year.of(200).isLeap(), false); + assertEquals(Year.of(300).isLeap(), false); + assertEquals(Year.of(400).isLeap(), true); + assertEquals(Year.of(500).isLeap(), false); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears() { + assertEquals(Year.of(2007).plusYears(-1), Year.of(2006)); + assertEquals(Year.of(2007).plusYears(0), Year.of(2007)); + assertEquals(Year.of(2007).plusYears(1), Year.of(2008)); + assertEquals(Year.of(2007).plusYears(2), Year.of(2009)); + + assertEquals(Year.of(Year.MAX_VALUE - 1).plusYears(1), Year.of(Year.MAX_VALUE)); + assertEquals(Year.of(Year.MAX_VALUE).plusYears(0), Year.of(Year.MAX_VALUE)); + + assertEquals(Year.of(Year.MIN_VALUE + 1).plusYears(-1), Year.of(Year.MIN_VALUE)); + assertEquals(Year.of(Year.MIN_VALUE).plusYears(0), Year.of(Year.MIN_VALUE)); + } + + @Test(groups={"tck"}) + public void test_plusYear_zero_equals() { + Year base = Year.of(2007); + assertEquals(base.plusYears(0), base); + } + + @Test(groups={"tck"}) + public void test_plusYears_big() { + long years = 20L + Year.MAX_VALUE; + assertEquals(Year.of(-40).plusYears(years), Year.of((int) (-40L + years))); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_max() { + Year.of(Year.MAX_VALUE).plusYears(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_maxLots() { + Year.of(Year.MAX_VALUE).plusYears(1000); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_min() { + Year.of(Year.MIN_VALUE).plusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_minLots() { + Year.of(Year.MIN_VALUE).plusYears(-1000); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears() { + assertEquals(Year.of(2007).minusYears(-1), Year.of(2008)); + assertEquals(Year.of(2007).minusYears(0), Year.of(2007)); + assertEquals(Year.of(2007).minusYears(1), Year.of(2006)); + assertEquals(Year.of(2007).minusYears(2), Year.of(2005)); + + assertEquals(Year.of(Year.MAX_VALUE - 1).minusYears(-1), Year.of(Year.MAX_VALUE)); + assertEquals(Year.of(Year.MAX_VALUE).minusYears(0), Year.of(Year.MAX_VALUE)); + + assertEquals(Year.of(Year.MIN_VALUE + 1).minusYears(1), Year.of(Year.MIN_VALUE)); + assertEquals(Year.of(Year.MIN_VALUE).minusYears(0), Year.of(Year.MIN_VALUE)); + } + + @Test(groups={"tck"}) + public void test_minusYear_zero_equals() { + Year base = Year.of(2007); + assertEquals(base.minusYears(0), base); + } + + @Test(groups={"tck"}) + public void test_minusYears_big() { + long years = 20L + Year.MAX_VALUE; + assertEquals(Year.of(40).minusYears(years), Year.of((int) (40L - years))); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_max() { + Year.of(Year.MAX_VALUE).minusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_maxLots() { + Year.of(Year.MAX_VALUE).minusYears(-1000); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_min() { + Year.of(Year.MIN_VALUE).minusYears(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_minLots() { + Year.of(Year.MIN_VALUE).minusYears(1000); + } + + //----------------------------------------------------------------------- + // adjustInto() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjustDate() { + LocalDate base = LocalDate.of(2007, 2, 12); + for (int i = -4; i <= 2104; i++) { + Temporal result = Year.of(i).adjustInto(base); + assertEquals(result, LocalDate.of(i, 2, 12)); + } + } + + @Test(groups={"tck"}) + public void test_adjustDate_resolve() { + Year test = Year.of(2011); + assertEquals(test.adjustInto(LocalDate.of(2012, 2, 29)), LocalDate.of(2011, 2, 28)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_adjustDate_nullLocalDate() { + Year test = Year.of(1); + test.adjustInto((LocalDate) null); + } + + //----------------------------------------------------------------------- + // length() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_length() { + assertEquals(Year.of(1999).length(), 365); + assertEquals(Year.of(2000).length(), 366); + assertEquals(Year.of(2001).length(), 365); + + assertEquals(Year.of(2007).length(), 365); + assertEquals(Year.of(2008).length(), 366); + assertEquals(Year.of(2009).length(), 365); + assertEquals(Year.of(2010).length(), 365); + assertEquals(Year.of(2011).length(), 365); + assertEquals(Year.of(2012).length(), 366); + + assertEquals(Year.of(2095).length(), 365); + assertEquals(Year.of(2096).length(), 366); + assertEquals(Year.of(2097).length(), 365); + assertEquals(Year.of(2098).length(), 365); + assertEquals(Year.of(2099).length(), 365); + assertEquals(Year.of(2100).length(), 365); + assertEquals(Year.of(2101).length(), 365); + assertEquals(Year.of(2102).length(), 365); + assertEquals(Year.of(2103).length(), 365); + assertEquals(Year.of(2104).length(), 366); + assertEquals(Year.of(2105).length(), 365); + + assertEquals(Year.of(-500).length(), 365); + assertEquals(Year.of(-400).length(), 366); + assertEquals(Year.of(-300).length(), 365); + assertEquals(Year.of(-200).length(), 365); + assertEquals(Year.of(-100).length(), 365); + assertEquals(Year.of(0).length(), 366); + assertEquals(Year.of(100).length(), 365); + assertEquals(Year.of(200).length(), 365); + assertEquals(Year.of(300).length(), 365); + assertEquals(Year.of(400).length(), 366); + assertEquals(Year.of(500).length(), 365); + } + + //----------------------------------------------------------------------- + // isValidMonthDay(Month) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isValidMonthDay_june() { + Year test = Year.of(2007); + MonthDay monthDay = MonthDay.of(6, 30); + assertEquals(test.isValidMonthDay(monthDay), true); + } + + @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); + } + + //----------------------------------------------------------------------- + // atMonth(Month) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atMonth() { + Year test = Year.of(2008); + assertEquals(test.atMonth(Month.JUNE), YearMonth.of(2008, 6)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_atMonth_nullMonth() { + Year test = Year.of(2008); + test.atMonth((Month) null); + } + + //----------------------------------------------------------------------- + // atMonth(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atMonth_int() { + Year test = Year.of(2008); + assertEquals(test.atMonth(6), YearMonth.of(2008, 6)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atMonth_int_invalidMonth() { + Year test = Year.of(2008); + test.atMonth(13); + } + + //----------------------------------------------------------------------- + // 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)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + 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) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_atDay_notLeapYear() { + Year test = Year.of(2007); + LocalDate expected = LocalDate.of(2007, 1, 1); + for (int i = 1; i <= 365; i++) { + assertEquals(test.atDay(i), expected); + expected = expected.plusDays(1); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atDay_notLeapYear_day366() { + Year test = Year.of(2007); + test.atDay(366); + } + + @Test(groups={"tck"}) + public void test_atDay_leapYear() { + Year test = Year.of(2008); + LocalDate expected = LocalDate.of(2008, 1, 1); + for (int i = 1; i <= 366; i++) { + assertEquals(test.atDay(i), expected); + expected = expected.plusDays(1); + } + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atDay_day0() { + Year test = Year.of(2007); + test.atDay(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atDay_day367() { + Year test = Year.of(2007); + test.atDay(367); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_compareTo() { + for (int i = -4; i <= 2104; i++) { + Year a = Year.of(i); + for (int j = -4; j <= 2104; j++) { + Year b = Year.of(j); + if (i < j) { + assertEquals(a.compareTo(b) < 0, true); + assertEquals(b.compareTo(a) > 0, true); + assertEquals(a.isAfter(b), false); + assertEquals(a.isBefore(b), true); + assertEquals(b.isAfter(a), true); + assertEquals(b.isBefore(a), false); + } else if (i > j) { + assertEquals(a.compareTo(b) > 0, true); + assertEquals(b.compareTo(a) < 0, true); + assertEquals(a.isAfter(b), true); + assertEquals(a.isBefore(b), false); + assertEquals(b.isAfter(a), false); + assertEquals(b.isBefore(a), true); + } else { + assertEquals(a.compareTo(b), 0); + assertEquals(b.compareTo(a), 0); + assertEquals(a.isAfter(b), false); + assertEquals(a.isBefore(b), false); + assertEquals(b.isAfter(a), false); + assertEquals(b.isBefore(a), false); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_nullYear() { + Year doy = null; + Year test = Year.of(1); + test.compareTo(doy); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + for (int i = -4; i <= 2104; i++) { + Year a = Year.of(i); + for (int j = -4; j <= 2104; j++) { + Year b = Year.of(j); + assertEquals(a.equals(b), i == j); + assertEquals(a.hashCode() == b.hashCode(), i == j); + } + } + } + + @Test(groups={"tck"}) + public void test_equals_same() { + Year test = Year.of(2011); + assertEquals(test.equals(test), true); + } + + @Test(groups={"tck"}) + public void test_equals_nullYear() { + Year doy = null; + Year test = Year.of(1); + assertEquals(test.equals(doy), false); + } + + @Test(groups={"tck"}) + public void test_equals_incorrectType() { + Year test = Year.of(1); + assertEquals(test.equals("Incorrect type"), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString() { + for (int i = -4; i <= 2104; i++) { + Year a = Year.of(i); + assertEquals(a.toString(), "" + i); + } + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("y"); + String t = Year.of(2010).toString(f); + assertEquals(t, "2010"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + Year.of(2010).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java b/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java new file mode 100644 index 00000000000..25d57f1a22b --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java @@ -0,0 +1,1046 @@ +/* + * 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.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.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +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; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +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.JulianFields; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.Year; +import java.time.temporal.YearMonth; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractDateTimeTest; + +/** + * Test YearMonth. + */ +@Test +public class TCKYearMonth extends AbstractDateTimeTest { + + private YearMonth TEST_2008_06; + + @BeforeMethod(groups={"tck", "implementation"}) + public void setUp() { + TEST_2008_06 = YearMonth.of(2008, 6); + } + + //----------------------------------------------------------------------- + @Override + protected List samples() { + TemporalAccessor[] array = {TEST_2008_06, }; + return Arrays.asList(array); + } + + @Override + protected List validFields() { + TemporalField[] array = { + MONTH_OF_YEAR, + EPOCH_MONTH, + YEAR_OF_ERA, + YEAR, + ERA, + }; + return Arrays.asList(array); + } + + @Override + protected List invalidFields() { + List list = new ArrayList<>(Arrays.asList(ChronoField.values())); + list.removeAll(validFields()); + list.add(JulianFields.JULIAN_DAY); + list.add(JulianFields.MODIFIED_JULIAN_DAY); + list.add(JulianFields.RATA_DIE); + return list; + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws IOException, ClassNotFoundException { + assertSerializable(TEST_2008_06); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(5); + dos.writeInt(2012); + dos.writeByte(9); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(YearMonth.of(2012, 9), bytes); + } + + //----------------------------------------------------------------------- + void check(YearMonth test, int y, int m) { + assertEquals(test.getYear(), y); + assertEquals(test.getMonth().getValue(), m); + } + + //----------------------------------------------------------------------- + // now() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now() { + YearMonth expected = YearMonth.now(Clock.systemDefaultZone()); + YearMonth test = YearMonth.now(); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = YearMonth.now(Clock.systemDefaultZone()); + test = YearMonth.now(); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(ZoneId) + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_ZoneId_nullZoneId() { + YearMonth.now((ZoneId) null); + } + + @Test(groups={"tck"}) + public void now_ZoneId() { + ZoneId zone = ZoneId.of("UTC+01:02:03"); + YearMonth expected = YearMonth.now(Clock.system(zone)); + YearMonth test = YearMonth.now(zone); + for (int i = 0; i < 100; i++) { + if (expected.equals(test)) { + return; + } + expected = YearMonth.now(Clock.system(zone)); + test = YearMonth.now(zone); + } + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + // now(Clock) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void now_Clock() { + Instant instant = LocalDateTime.of(2010, 12, 31, 0, 0).toInstant(ZoneOffset.UTC); + Clock clock = Clock.fixed(instant, ZoneOffset.UTC); + YearMonth test = YearMonth.now(clock); + assertEquals(test.getYear(), 2010); + assertEquals(test.getMonth(), Month.DECEMBER); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void now_Clock_nullClock() { + YearMonth.now((Clock) null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_intsMonth() { + YearMonth test = YearMonth.of(2008, Month.FEBRUARY); + check(test, 2008, 2); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_intsMonth_yearTooLow() { + YearMonth.of(Year.MIN_VALUE - 1, Month.JANUARY); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_intsMonth_dayTooHigh() { + YearMonth.of(Year.MAX_VALUE + 1, Month.JANUARY); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_intsMonth_nullMonth() { + YearMonth.of(2008, null); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_ints() { + YearMonth test = YearMonth.of(2008, 2); + check(test, 2008, 2); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_yearTooLow() { + YearMonth.of(Year.MIN_VALUE - 1, 2); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_dayTooHigh() { + YearMonth.of(Year.MAX_VALUE + 1, 2); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_monthTooLow() { + YearMonth.of(2008, 0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_ints_monthTooHigh() { + YearMonth.of(2008, 13); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_factory_CalendricalObject() { + assertEquals(YearMonth.from(LocalDate.of(2007, 7, 15)), YearMonth.of(2007, 7)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_factory_CalendricalObject_invalid_noDerive() { + YearMonth.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_CalendricalObject_null() { + YearMonth.from((TemporalAccessor) null); + } + + //----------------------------------------------------------------------- + // parse() + //----------------------------------------------------------------------- + @DataProvider(name="goodParseData") + Object[][] provider_goodParseData() { + return new Object[][] { + {"0000-01", YearMonth.of(0, 1)}, + {"0000-12", YearMonth.of(0, 12)}, + {"9999-12", YearMonth.of(9999, 12)}, + {"2000-01", YearMonth.of(2000, 1)}, + {"2000-02", YearMonth.of(2000, 2)}, + {"2000-03", YearMonth.of(2000, 3)}, + {"2000-04", YearMonth.of(2000, 4)}, + {"2000-05", YearMonth.of(2000, 5)}, + {"2000-06", YearMonth.of(2000, 6)}, + {"2000-07", YearMonth.of(2000, 7)}, + {"2000-08", YearMonth.of(2000, 8)}, + {"2000-09", YearMonth.of(2000, 9)}, + {"2000-10", YearMonth.of(2000, 10)}, + {"2000-11", YearMonth.of(2000, 11)}, + {"2000-12", YearMonth.of(2000, 12)}, + + {"+12345678-03", YearMonth.of(12345678, 3)}, + {"+123456-03", YearMonth.of(123456, 3)}, + {"0000-03", YearMonth.of(0, 3)}, + {"-1234-03", YearMonth.of(-1234, 3)}, + {"-12345678-03", YearMonth.of(-12345678, 3)}, + + {"+" + Year.MAX_VALUE + "-03", YearMonth.of(Year.MAX_VALUE, 3)}, + {Year.MIN_VALUE + "-03", YearMonth.of(Year.MIN_VALUE, 3)}, + }; + } + + @Test(dataProvider="goodParseData", groups={"tck"}) + public void factory_parse_success(String text, YearMonth expected) { + YearMonth yearMonth = YearMonth.parse(text); + assertEquals(yearMonth, expected); + } + + //----------------------------------------------------------------------- + @DataProvider(name="badParseData") + Object[][] provider_badParseData() { + return new Object[][] { + {"", 0}, + {"-00", 1}, + {"--01-0", 1}, + {"A01-3", 0}, + {"200-01", 0}, + {"2009/12", 4}, + + {"-0000-10", 0}, + {"-12345678901-10", 11}, + {"+1-10", 1}, + {"+12-10", 1}, + {"+123-10", 1}, + {"+1234-10", 0}, + {"12345-10", 0}, + {"+12345678901-10", 11}, + }; + } + + @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_fail(String text, int pos) { + try { + YearMonth.parse(text); + fail(String.format("Parse should have failed for %s at position %d", text, pos)); + } catch (DateTimeParseException ex) { + assertEquals(ex.getParsedString(), text); + assertEquals(ex.getErrorIndex(), pos); + throw ex; + } + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + public void factory_parse_illegalValue_Month() { + YearMonth.parse("2008-13"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_nullText() { + YearMonth.parse(null); + } + + //----------------------------------------------------------------------- + // parse(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_parse_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("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"); + YearMonth.parse((String) null, f); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_parse_formatter_nullFormatter() { + YearMonth.parse("ANY", null); + } + + //----------------------------------------------------------------------- + // get(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_get_TemporalField() { + assertEquals(TEST_2008_06.get(ChronoField.YEAR), 2008); + assertEquals(TEST_2008_06.get(ChronoField.MONTH_OF_YEAR), 6); + assertEquals(TEST_2008_06.get(ChronoField.YEAR_OF_ERA), 2008); + assertEquals(TEST_2008_06.get(ChronoField.ERA), 1); + } + + @Test + public void test_getLong_TemporalField() { + assertEquals(TEST_2008_06.getLong(ChronoField.YEAR), 2008); + assertEquals(TEST_2008_06.getLong(ChronoField.MONTH_OF_YEAR), 6); + assertEquals(TEST_2008_06.getLong(ChronoField.YEAR_OF_ERA), 2008); + assertEquals(TEST_2008_06.getLong(ChronoField.ERA), 1); + assertEquals(TEST_2008_06.getLong(ChronoField.EPOCH_MONTH), (2008 - 1970) * 12 + 6 - 1); + } + + //----------------------------------------------------------------------- + // get*() + //----------------------------------------------------------------------- + @DataProvider(name="sampleDates") + Object[][] provider_sampleDates() { + return new Object[][] { + {2008, 1}, + {2008, 2}, + {-1, 3}, + {0, 12}, + }; + } + + //----------------------------------------------------------------------- + // with(Year) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_Year() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.with(Year.of(2000)), YearMonth.of(2000, 6)); + } + + @Test(groups={"tck"}) + public void test_with_Year_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.with(Year.of(2008)), test); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_Year_null() { + YearMonth test = YearMonth.of(2008, 6); + test.with((Year) null); + } + + //----------------------------------------------------------------------- + // with(Month) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_with_Month() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.with(Month.JANUARY), YearMonth.of(2008, 1)); + } + + @Test(groups={"tck"}) + public void test_with_Month_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.with(Month.JUNE), test); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_with_Month_null() { + YearMonth test = YearMonth.of(2008, 6); + test.with((Month) null); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.withYear(1999), YearMonth.of(1999, 6)); + } + + @Test(groups={"tck"}) + public void test_withYear_int_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.withYear(2008), test); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withYear_tooLow() { + YearMonth test = YearMonth.of(2008, 6); + test.withYear(Year.MIN_VALUE - 1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withYear_tooHigh() { + YearMonth test = YearMonth.of(2008, 6); + test.withYear(Year.MAX_VALUE + 1); + } + + //----------------------------------------------------------------------- + // withMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withMonth() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.withMonth(1), YearMonth.of(2008, 1)); + } + + @Test(groups={"tck"}) + public void test_withMonth_int_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.withMonth(6), test); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooLow() { + YearMonth test = YearMonth.of(2008, 6); + test.withMonth(0); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_withMonth_tooHigh() { + YearMonth test = YearMonth.of(2008, 6); + test.withMonth(13); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusYears_long() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusYears(1), YearMonth.of(2009, 6)); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusYears(0), test); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_negative() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusYears(-1), YearMonth.of(2007, 6)); + } + + @Test(groups={"tck"}) + public void test_plusYears_long_big() { + YearMonth test = YearMonth.of(-40, 6); + assertEquals(test.plusYears(20L + Year.MAX_VALUE), YearMonth.of((int) (-40L + 20L + Year.MAX_VALUE), 6)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLarge() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 6); + test.plusYears(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLargeMaxAddMax() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.plusYears(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooLargeMaxAddMin() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.plusYears(Long.MIN_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusYears_long_invalidTooSmall() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 6); + test.plusYears(-1); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_plusMonths_long() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusMonths(1), YearMonth.of(2008, 7)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusMonths(0), test); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_overYears() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusMonths(7), YearMonth.of(2009, 1)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_negative() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusMonths(-1), YearMonth.of(2008, 5)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_negativeOverYear() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.plusMonths(-6), YearMonth.of(2007, 12)); + } + + @Test(groups={"tck"}) + public void test_plusMonths_long_big() { + YearMonth test = YearMonth.of(-40, 6); + long months = 20L + Integer.MAX_VALUE; + assertEquals(test.plusMonths(months), YearMonth.of((int) (-40L + months / 12), 6 + (int) (months % 12))); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusMonths_long_invalidTooLarge() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.plusMonths(1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_long_invalidTooLargeMaxAddMax() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.plusMonths(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_plusMonths_long_invalidTooLargeMaxAddMin() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.plusMonths(Long.MIN_VALUE); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_plusMonths_long_invalidTooSmall() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 1); + test.plusMonths(-1); + } + + //----------------------------------------------------------------------- + // minusYears() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusYears_long() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusYears(1), YearMonth.of(2007, 6)); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusYears(0), test); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_negative() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusYears(-1), YearMonth.of(2009, 6)); + } + + @Test(groups={"tck"}) + public void test_minusYears_long_big() { + YearMonth test = YearMonth.of(40, 6); + assertEquals(test.minusYears(20L + Year.MAX_VALUE), YearMonth.of((int) (40L - 20L - Year.MAX_VALUE), 6)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLarge() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 6); + test.minusYears(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLargeMaxSubtractMax() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 12); + test.minusYears(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooLargeMaxSubtractMin() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 12); + test.minusYears(Long.MIN_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusYears_long_invalidTooSmall() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 6); + test.minusYears(1); + } + + //----------------------------------------------------------------------- + // minusMonths() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_minusMonths_long() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusMonths(1), YearMonth.of(2008, 5)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_noChange_equal() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusMonths(0), test); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_overYears() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusMonths(6), YearMonth.of(2007, 12)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_negative() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusMonths(-1), YearMonth.of(2008, 7)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_negativeOverYear() { + YearMonth test = YearMonth.of(2008, 6); + assertEquals(test.minusMonths(-7), YearMonth.of(2009, 1)); + } + + @Test(groups={"tck"}) + public void test_minusMonths_long_big() { + YearMonth test = YearMonth.of(40, 6); + long months = 20L + Integer.MAX_VALUE; + assertEquals(test.minusMonths(months), YearMonth.of((int) (40L - months / 12), 6 - (int) (months % 12))); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusMonths_long_invalidTooLarge() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.minusMonths(-1); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_long_invalidTooLargeMaxSubtractMax() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.minusMonths(Long.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_minusMonths_long_invalidTooLargeMaxSubtractMin() { + YearMonth test = YearMonth.of(Year.MAX_VALUE, 12); + test.minusMonths(Long.MIN_VALUE); + } + + @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) + public void test_minusMonths_long_invalidTooSmall() { + YearMonth test = YearMonth.of(Year.MIN_VALUE, 1); + test.minusMonths(1); + } + + //----------------------------------------------------------------------- + // adjustInto() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjustDate() { + YearMonth test = YearMonth.of(2008, 6); + LocalDate date = LocalDate.of(2007, 1, 1); + assertEquals(test.adjustInto(date), LocalDate.of(2008, 6, 1)); + } + + @Test(groups={"tck"}) + public void test_adjustDate_preserveDoM() { + YearMonth test = YearMonth.of(2011, 3); + LocalDate date = LocalDate.of(2008, 2, 29); + assertEquals(test.adjustInto(date), LocalDate.of(2011, 3, 29)); + } + + @Test(groups={"tck"}) + public void test_adjustDate_resolve() { + YearMonth test = YearMonth.of(2007, 2); + LocalDate date = LocalDate.of(2008, 3, 31); + assertEquals(test.adjustInto(date), LocalDate.of(2007, 2, 28)); + } + + @Test(groups={"tck"}) + public void test_adjustDate_equal() { + YearMonth test = YearMonth.of(2008, 6); + LocalDate date = LocalDate.of(2008, 6, 30); + assertEquals(test.adjustInto(date), date); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_adjustDate_null() { + TEST_2008_06.adjustInto((LocalDate) null); + } + + //----------------------------------------------------------------------- + // isLeapYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isLeapYear() { + assertEquals(YearMonth.of(2007, 6).isLeapYear(), false); + assertEquals(YearMonth.of(2008, 6).isLeapYear(), true); + } + + //----------------------------------------------------------------------- + // lengthOfMonth() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_lengthOfMonth_june() { + YearMonth test = YearMonth.of(2007, 6); + assertEquals(test.lengthOfMonth(), 30); + } + + @Test(groups={"tck"}) + public void test_lengthOfMonth_febNonLeap() { + YearMonth test = YearMonth.of(2007, 2); + assertEquals(test.lengthOfMonth(), 28); + } + + @Test(groups={"tck"}) + public void test_lengthOfMonth_febLeap() { + YearMonth test = YearMonth.of(2008, 2); + assertEquals(test.lengthOfMonth(), 29); + } + + //----------------------------------------------------------------------- + // lengthOfYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_lengthOfYear() { + assertEquals(YearMonth.of(2007, 6).lengthOfYear(), 365); + assertEquals(YearMonth.of(2008, 6).lengthOfYear(), 366); + } + + //----------------------------------------------------------------------- + // isValidDay(int) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isValidDay_int_june() { + YearMonth test = YearMonth.of(2007, 6); + assertEquals(test.isValidDay(1), true); + assertEquals(test.isValidDay(30), true); + + assertEquals(test.isValidDay(-1), false); + assertEquals(test.isValidDay(0), false); + assertEquals(test.isValidDay(31), false); + assertEquals(test.isValidDay(32), false); + } + + @Test(groups={"tck"}) + public void test_isValidDay_int_febNonLeap() { + YearMonth test = YearMonth.of(2007, 2); + assertEquals(test.isValidDay(1), true); + assertEquals(test.isValidDay(28), true); + + assertEquals(test.isValidDay(-1), false); + assertEquals(test.isValidDay(0), false); + assertEquals(test.isValidDay(29), false); + assertEquals(test.isValidDay(32), false); + } + + @Test(groups={"tck"}) + public void test_isValidDay_int_febLeap() { + YearMonth test = YearMonth.of(2008, 2); + assertEquals(test.isValidDay(1), true); + assertEquals(test.isValidDay(29), true); + + assertEquals(test.isValidDay(-1), false); + assertEquals(test.isValidDay(0), false); + assertEquals(test.isValidDay(30), false); + assertEquals(test.isValidDay(32), false); + } + + //----------------------------------------------------------------------- + // 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)); + } + + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + public void test_atDay_int_invalidDay() { + YearMonth test = YearMonth.of(2008, 6); + test.atDay(31); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_comparisons() { + doTest_comparisons_YearMonth( + YearMonth.of(-1, 1), + YearMonth.of(0, 1), + YearMonth.of(0, 12), + YearMonth.of(1, 1), + YearMonth.of(1, 2), + YearMonth.of(1, 12), + YearMonth.of(2008, 1), + YearMonth.of(2008, 6), + YearMonth.of(2008, 12) + ); + } + + void doTest_comparisons_YearMonth(YearMonth... localDates) { + for (int i = 0; i < localDates.length; i++) { + YearMonth a = localDates[i]; + for (int j = 0; j < localDates.length; j++) { + YearMonth b = localDates[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_compareTo_ObjectNull() { + TEST_2008_06.compareTo(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isBefore_ObjectNull() { + TEST_2008_06.isBefore(null); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_isAfter_ObjectNull() { + TEST_2008_06.isAfter(null); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + YearMonth a = YearMonth.of(2008, 6); + YearMonth b = YearMonth.of(2008, 6); + YearMonth c = YearMonth.of(2007, 6); + YearMonth d = YearMonth.of(2008, 5); + + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(a.equals(c), false); + assertEquals(a.equals(d), false); + + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + assertEquals(b.equals(c), false); + assertEquals(b.equals(d), false); + + assertEquals(c.equals(a), false); + assertEquals(c.equals(b), false); + assertEquals(c.equals(c), true); + assertEquals(c.equals(d), false); + + assertEquals(d.equals(a), false); + assertEquals(d.equals(b), false); + assertEquals(d.equals(c), false); + assertEquals(d.equals(d), true); + } + + @Test(groups={"tck"}) + public void test_equals_itself_true() { + assertEquals(TEST_2008_06.equals(TEST_2008_06), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + assertEquals(TEST_2008_06.equals("2007-07-15"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + assertEquals(TEST_2008_06.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(dataProvider="sampleDates", groups={"tck"}) + public void test_hashCode(int y, int m) { + YearMonth a = YearMonth.of(y, m); + assertEquals(a.hashCode(), a.hashCode()); + YearMonth b = YearMonth.of(y, m); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_hashCode_unique() { + Set uniques = new HashSet(201 * 12); + for (int i = 1900; i <= 2100; i++) { + for (int j = 1; j <= 12; j++) { + assertTrue(uniques.add(YearMonth.of(i, j).hashCode())); + } + } + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="sampleToString") + Object[][] provider_sampleToString() { + return new Object[][] { + {2008, 1, "2008-01"}, + {2008, 12, "2008-12"}, + {7, 5, "0007-05"}, + {0, 5, "0000-05"}, + {-1, 1, "-0001-01"}, + }; + } + + @Test(dataProvider="sampleToString", groups={"tck"}) + public void test_toString(int y, int m, String expected) { + YearMonth test = YearMonth.of(y, m); + String str = test.toString(); + assertEquals(str, expected); + } + + //----------------------------------------------------------------------- + // toString(DateTimeFormatter) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_formatter() { + DateTimeFormatter f = DateTimeFormatters.pattern("y M"); + String t = YearMonth.of(2010, 12).toString(f); + assertEquals(t, "2010 12"); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_toString_formatter_null() { + YearMonth.of(2010, 12).toString(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChrono.java b/jdk/test/java/time/tck/java/time/temporal/TestChrono.java new file mode 100644 index 00000000000..cd30519dd04 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TestChrono.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) 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 org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +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.util.Locale; +import java.util.Set; + +import java.time.temporal.Chrono; +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 org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Chrono 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 + } + + //----------------------------------------------------------------------- + // regular data factory for names and descriptions of available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Object[][] data_of_calendars() { + return new Object[][] { + {"Hijrah", "islamicc", "Hijrah calendar"}, + {"ISO", "iso8601", "ISO calendar"}, + {"Japanese", "japanese", "Japanese calendar"}, + {"Minguo", "roc", "Minguo Calendar"}, + {"ThaiBuddhist", "buddhist", "ThaiBuddhist calendar"}, + }; + } + + @Test(dataProvider = "calendars") + public void test_getters(String chronoId, String calendarSystemType, String description) { + Chrono chrono = Chrono.of(chronoId); + assertNotNull(chrono, "Required calendar not found by ID: " + chronoId); + assertEquals(chrono.getId(), chronoId); + assertEquals(chrono.getCalendarType(), calendarSystemType); + } + + @Test(dataProvider = "calendars") + public void test_required_calendars(String chronoId, String calendarSystemType, String description) { + Chrono chrono = Chrono.of(chronoId); + assertNotNull(chrono, "Required calendar not found by ID: " + chronoId); + chrono = Chrono.of(calendarSystemType); + assertNotNull(chrono, "Required calendar not found by type: " + chronoId); + Set> cals = Chrono.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(); + assertNotNull(chronos, "Required list of calendars must be non-null"); + for (Chrono chrono : chronos) { + Chrono lookup = Chrono.of(chrono.getId()); + assertNotNull(lookup, "Required calendar not found: " + chrono); + } + assertEquals(chronos.size() >= data_of_calendars().length, true, "Chrono.getAvailableChronologies().size = " + chronos.size() + + ", expected >= " + data_of_calendars().length); + } + + /** + * Compute the number of days from the Epoch and compute the date from the number of days. + */ + @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 + ChronoLocalDate date1 = chrono.dateNow(); + long epoch1 = date1.getLong(ChronoField.EPOCH_DAY); + ChronoLocalDate date2 = date1.with(ChronoField.EPOCH_DAY, epoch1); + assertEquals(date1, date2, "Date from epoch day is not same date: " + date1 + " != " + date2); + long epoch2 = date1.getLong(ChronoField.EPOCH_DAY); + assertEquals(epoch1, epoch2, "Epoch day not the same: " + epoch1 + " != " + epoch2); + } + + //----------------------------------------------------------------------- + // locale based lookup + //----------------------------------------------------------------------- + @DataProvider(name = "calendarsystemtype") + Object[][] data_CalendarType() { + return new Object[][] { + {HijrahChrono.INSTANCE, "islamicc"}, + {ISOChrono.INSTANCE, "iso8601"}, + {JapaneseChrono.INSTANCE, "japanese"}, + {MinguoChrono.INSTANCE, "roc"}, + {ThaiBuddhistChrono.INSTANCE, "buddhist"}, + }; + } + + @Test(dataProvider = "calendarsystemtype", groups="tck") + public void test_getCalendarType(Chrono chrono, String calendarType) { + assertEquals(chrono.getCalendarType(), calendarType); + } + + @Test(dataProvider = "calendarsystemtype", groups="tck") + public void test_lookupLocale(Chrono chrono, String calendarType) { + Locale locale = new Locale.Builder().setLanguage("en").setRegion("CA").setUnicodeLocaleKeyword("ca", calendarType).build(); + assertEquals(Chrono.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; + 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"); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java new file mode 100644 index 00000000000..95caf573a68 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java @@ -0,0 +1,503 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +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; + +/** + * Test assertions that must be true for the built-in ISO chronology. + */ +@Test +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}, + }; + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badWithAdjusterChrono(Chrono 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); + TemporalAdjuster adjuster = new FixedAdjuster(date2); + if (chrono != chrono2) { + try { + date.with(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.with(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusAdjusterChrono(Chrono 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); + if (chrono != chrono2) { + try { + date.plus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.plus(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusAdjusterChrono(Chrono 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); + if (chrono != chrono2) { + try { + date.minus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException"); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.minus(adjuster); + assertEquals(result, date2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusTemporalUnitChrono(Chrono 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); + TemporalUnit adjuster = new FixedTemporalUnit(date2); + if (chrono != chrono2) { + try { + date.plus(1, adjuster); + Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + 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) { + 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); + TemporalUnit adjuster = new FixedTemporalUnit(date2); + if (chrono != chrono2) { + try { + date.minus(1, adjuster); + Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + 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) { + 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); + TemporalField adjuster = new FixedTemporalField(date2); + if (chrono != chrono2) { + try { + date.with(adjuster, 1); + Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + date.getClass() + + ", can not be cast to " + date2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDate result = date.with(adjuster, 1); + assertEquals(result, date2, "TemporalField doWith() failed to replace date"); + } + } + } + + //----------------------------------------------------------------------- + // isBefore, isAfter, isEqual, DATE_COMPARATOR + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="calendars") + public void test_date_comparisons(Chrono chrono) { + List> dates = new ArrayList<>(); + + ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); + + // Insert dates in order, no duplicates + dates.add(date.minus(1000, ChronoUnit.YEARS)); + dates.add(date.minus(100, ChronoUnit.YEARS)); + dates.add(date.minus(10, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(10, ChronoUnit.YEARS)); + dates.add(date.plus(100, ChronoUnit.YEARS)); + 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) { + 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); + for (int j = 0; j < otherDates.size(); j++) { + ChronoLocalDate b = otherDates.get(j); + int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b); + if (i < j) { + assertTrue(cmp < 0, a + " compare " + b); + assertEquals(a.isBefore(b), true, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else if (i > j) { + assertTrue(cmp > 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), true, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else { + assertTrue(cmp == 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), true, a + " isEqual " + b); + } + } + } + } + } + + public void test_date_comparator_checkGenerics_ISO() { + List> dates = new ArrayList<>(); + ChronoLocalDate date = LocalDate.of(1900, 1, 1); + + // Insert dates in order, no duplicates + dates.add(date.minus(10, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(10, ChronoUnit.YEARS)); + + List> copy = new ArrayList<>(dates); + Collections.shuffle(copy); + Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR); + assertEquals(copy, dates); + assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0); + } + + public void test_date_comparator_checkGenerics_LocalDate() { + List dates = new ArrayList<>(); + LocalDate date = LocalDate.of(1900, 1, 1); + + // Insert dates in order, no duplicates + dates.add(date.minus(10, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(10, ChronoUnit.YEARS)); + + List copy = new ArrayList<>(dates); + Collections.shuffle(copy); + Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR); + assertEquals(copy, dates); + assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0); + } + + //----------------------------------------------------------------------- + // Test Serialization of ISO via chrono API + //----------------------------------------------------------------------- + @Test( groups={"tck"}, dataProvider="calendars") + public > void test_ChronoSerialization(C chrono) throws Exception { + LocalDate ref = LocalDate.of(2000, 1, 5); + ChronoLocalDate orginal = chrono.date(ref); + 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") + ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); + assertEquals(ser, orginal, "deserialized date is wrong"); + } + + /** + * 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 { + private Temporal datetime; + + FixedAdjuster(Temporal datetime) { + this.datetime = datetime; + } + + @Override + public Temporal adjustInto(Temporal ignore) { + return datetime; + } + + @Override + public Temporal addTo(Temporal ignore) { + return datetime; + } + + @Override + public Temporal subtractFrom(Temporal ignore) { + return datetime; + } + + } + + /** + * FixedTemporalUnit returns a fixed Temporal in all adjustments. + * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + */ + static class FixedTemporalUnit implements TemporalUnit { + private Temporal temporal; + + FixedTemporalUnit(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalUnit"; + } + + @Override + public Duration getDuration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDurationEstimated() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSupported(Temporal temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) this.temporal; + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + 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. + */ + static class FixedTemporalField implements TemporalField { + private Temporal temporal; + FixedTemporalField(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalField"; + } + + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange range() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(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 new file mode 100644 index 00000000000..c51be6c69b8 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java @@ -0,0 +1,470 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +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.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 java.time.calendar.HijrahChrono; +import java.time.calendar.JapaneseChrono; +import java.time.calendar.MinguoChrono; +import java.time.calendar.ThaiBuddhistChrono; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test assertions that must be true for all built-in chronologies. + */ +@Test +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}}; + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badWithAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalAdjuster adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + cdt.with(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.with(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalAdder adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + cdt.plus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.plus(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date time"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusAdjusterChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalSubtractor adjuster = new FixedAdjuster(cdt2); + if (chrono != chrono2) { + try { + cdt.minus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + cdt + ", supplied: " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.minus(adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusTemporalUnitChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalUnit adjuster = new FixedTemporalUnit(cdt2); + if (chrono != chrono2) { + try { + cdt.plus(1, adjuster); + Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + cdt + + ", can not be cast to " + cdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.plus(1, adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusTemporalUnitChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalUnit adjuster = new FixedTemporalUnit(cdt2); + if (chrono != chrono2) { + try { + cdt.minus(1, adjuster); + Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + cdt.getClass() + + ", can not be cast to " + cdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.minus(1, adjuster); + assertEquals(result, cdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badTemporalFieldChrono(Chrono 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]; + ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); + TemporalField adjuster = new FixedTemporalField(cdt2); + if (chrono != chrono2) { + try { + cdt.with(adjuster, 1); + Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + cdt.getClass() + + ", can not be cast to " + cdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoLocalDateTime result = cdt.with(adjuster, 1); + assertEquals(result, cdt2, "TemporalField doWith() failed to replace date"); + } + } + } + + //----------------------------------------------------------------------- + // isBefore, isAfter, isEqual + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="calendars") + public void test_datetime_comparisons(Chrono chrono) { + List> dates = new ArrayList<>(); + + ChronoLocalDateTime date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN); + + // Insert dates in order, no duplicates + dates.add(date.minus(100, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date.minus(1, ChronoUnit.HOURS)); + dates.add(date.minus(1, ChronoUnit.MINUTES)); + dates.add(date.minus(1, ChronoUnit.SECONDS)); + dates.add(date.minus(1, ChronoUnit.NANOS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.NANOS)); + dates.add(date.plus(1, ChronoUnit.SECONDS)); + dates.add(date.plus(1, ChronoUnit.MINUTES)); + dates.add(date.plus(1, ChronoUnit.HOURS)); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(100, 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 (ChronoLocalDateTime d : dates) { + otherDates.add(chrono2.date(d).atTime(d.getTime())); + } + + // Now compare the sequence of original dates with the sequence of converted dates + for (int i = 0; i < dates.size(); i++) { + ChronoLocalDateTime a = dates.get(i); + for (int j = 0; j < otherDates.size(); j++) { + ChronoLocalDateTime b = otherDates.get(j); + int cmp = ChronoLocalDateTime.DATE_TIME_COMPARATOR.compare(a, b); + if (i < j) { + assertTrue(cmp < 0, a + " compare " + b); + assertEquals(a.isBefore(b), true, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else if (i > j) { + assertTrue(cmp > 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), true, a + " isAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else { + assertTrue(cmp == 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " isAfter " + b); + assertEquals(a.isEqual(b), true, a + " isEqual " + b); + } + } + } + } + } + + //----------------------------------------------------------------------- + // Test Serialization of ISO via chrono API + //----------------------------------------------------------------------- + @Test( groups={"tck"}, dataProvider="calendars") + public > void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception { + LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3); + ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.getTime()); + 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") + ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); + assertEquals(ser, orginal, "deserialized date is wrong"); + } + + /** + * 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 { + private Temporal datetime; + + FixedAdjuster(Temporal datetime) { + this.datetime = datetime; + } + + @Override + public Temporal adjustInto(Temporal ignore) { + return datetime; + } + + @Override + public Temporal addTo(Temporal ignore) { + return datetime; + } + + @Override + public Temporal subtractFrom(Temporal ignore) { + return datetime; + } + + } + + /** + * FixedTemporalUnit returns a fixed Temporal in all adjustments. + * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + */ + static class FixedTemporalUnit implements TemporalUnit { + private Temporal temporal; + + FixedTemporalUnit(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalUnit"; + } + + @Override + public Duration getDuration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDurationEstimated() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSupported(Temporal temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) this.temporal; + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + 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. + */ + static class FixedTemporalField implements TemporalField { + private Temporal temporal; + FixedTemporalField(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalField"; + } + + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange range() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(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 new file mode 100644 index 00000000000..e89725bb3d3 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java @@ -0,0 +1,475 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +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.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.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 org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test assertions that must be true for all built-in chronologies. + */ +@Test +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}, + }; + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badWithAdjusterChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalAdjuster adjuster = new FixedAdjuster(czdt2); + if (chrono != chrono2) { + try { + czdt.with(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + czdt + ", supplied: " + czdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + ChronoZonedDateTime result = czdt.with(adjuster); + assertEquals(result, czdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusAdjusterChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalAdder adjuster = new FixedAdjuster(czdt2); + if (chrono != chrono2) { + try { + czdt.plus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + czdt + ", supplied: " + czdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoZonedDateTime result = czdt.plus(adjuster); + assertEquals(result, czdt2, "WithAdjuster failed to replace date time"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusAdjusterChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalSubtractor adjuster = new FixedAdjuster(czdt2); + if (chrono != chrono2) { + try { + czdt.minus(adjuster); + Assert.fail("WithAdjuster should have thrown a ClassCastException, " + + "required: " + czdt + ", supplied: " + czdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoZonedDateTime result = czdt.minus(adjuster); + assertEquals(result, czdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badPlusTemporalUnitChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalUnit adjuster = new FixedTemporalUnit(czdt2); + if (chrono != chrono2) { + try { + czdt.plus(1, adjuster); + Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException, " + czdt + + " can not be cast to " + czdt2); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoZonedDateTime result = czdt.plus(1, adjuster); + assertEquals(result, czdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badMinusTemporalUnitChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalUnit adjuster = new FixedTemporalUnit(czdt2); + if (chrono != chrono2) { + try { + czdt.minus(1, adjuster); + Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException, " + czdt.getClass() + + " can not be cast to " + czdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoZonedDateTime result = czdt.minus(1, adjuster); + assertEquals(result, czdt2, "WithAdjuster failed to replace date"); + } + } + } + + @Test(groups={"tck"}, dataProvider="calendars") + public void test_badTemporalFieldChrono(Chrono 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]; + ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); + TemporalField adjuster = new FixedTemporalField(czdt2); + if (chrono != chrono2) { + try { + czdt.with(adjuster, 1); + Assert.fail("TemporalField doWith() should have thrown a ClassCastException, " + czdt.getClass() + + " can not be cast to " + czdt2.getClass()); + } catch (ClassCastException cce) { + // Expected exception; not an error + } + } else { + // Same chronology, + ChronoZonedDateTime result = czdt.with(adjuster, 1); + assertEquals(result, czdt2, "TemporalField doWith() failed to replace date"); + } + } + } + + //----------------------------------------------------------------------- + // isBefore, isAfter, isEqual, INSTANT_COMPARATOR test a Chrono against the other Chronos + //----------------------------------------------------------------------- + @Test(groups={"tck"}, dataProvider="calendars") + public void test_zonedDateTime_comparisons(Chrono chrono) { + List> dates = new ArrayList<>(); + + ChronoZonedDateTime date = chrono.date(LocalDate.of(1900, 1, 1)) + .atTime(LocalTime.MIN) + .atZone(ZoneOffset.UTC); + + // Insert dates in order, no duplicates + dates.add(date.minus(100, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.YEARS)); + dates.add(date.minus(1, ChronoUnit.MONTHS)); + dates.add(date.minus(1, ChronoUnit.WEEKS)); + dates.add(date.minus(1, ChronoUnit.DAYS)); + dates.add(date.minus(1, ChronoUnit.HOURS)); + dates.add(date.minus(1, ChronoUnit.MINUTES)); + dates.add(date.minus(1, ChronoUnit.SECONDS)); + dates.add(date.minus(1, ChronoUnit.NANOS)); + dates.add(date); + dates.add(date.plus(1, ChronoUnit.NANOS)); + dates.add(date.plus(1, ChronoUnit.SECONDS)); + dates.add(date.plus(1, ChronoUnit.MINUTES)); + dates.add(date.plus(1, ChronoUnit.HOURS)); + dates.add(date.plus(1, ChronoUnit.DAYS)); + dates.add(date.plus(1, ChronoUnit.WEEKS)); + dates.add(date.plus(1, ChronoUnit.MONTHS)); + dates.add(date.plus(1, ChronoUnit.YEARS)); + dates.add(date.plus(100, ChronoUnit.YEARS)); + + // Check these dates against the corresponding dates for every calendar + for (Chrono[] clist : data_of_calendars()) { + List> otherDates = new ArrayList<>(); + Chrono chrono2 = ISOChrono.INSTANCE; //clist[0]; + for (ChronoZonedDateTime d : dates) { + otherDates.add(chrono2.date(d).atTime(d.getTime()).atZone(d.getZone())); + } + + // Now compare the sequence of original dates with the sequence of converted dates + for (int i = 0; i < dates.size(); i++) { + ChronoZonedDateTime a = dates.get(i); + for (int j = 0; j < otherDates.size(); j++) { + ChronoZonedDateTime b = otherDates.get(j); + int cmp = ChronoZonedDateTime.INSTANT_COMPARATOR.compare(a, b); + if (i < j) { + assertTrue(cmp < 0, a + " compare " + b); + assertEquals(a.isBefore(b), true, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " ifAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else if (i > j) { + assertTrue(cmp > 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), true, a + " ifAfter " + b); + assertEquals(a.isEqual(b), false, a + " isEqual " + b); + } else { + assertTrue(cmp == 0, a + " compare " + b); + assertEquals(a.isBefore(b), false, a + " isBefore " + b); + assertEquals(a.isAfter(b), false, a + " ifAfter " + b); + assertEquals(a.isEqual(b), true, a + " isEqual " + b); + } + } + } + } + } + + //----------------------------------------------------------------------- + // Test Serialization of ISO via chrono API + //----------------------------------------------------------------------- + @Test( groups={"tck"}, dataProvider="calendars") + public > void test_ChronoZonedDateTimeSerialization(C 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()); + 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") + ChronoZonedDateTime ser = (ChronoZonedDateTime) in.readObject(); + assertEquals(ser, orginal, "deserialized date is wrong"); + } + + + /** + * 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 { + private Temporal datetime; + + FixedAdjuster(Temporal datetime) { + this.datetime = datetime; + } + + @Override + public Temporal adjustInto(Temporal ignore) { + return datetime; + } + + @Override + public Temporal addTo(Temporal ignore) { + return datetime; + } + + @Override + public Temporal subtractFrom(Temporal ignore) { + return datetime; + } + + } + + /** + * FixedTemporalUnit returns a fixed Temporal in all adjustments. + * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + */ + static class FixedTemporalUnit implements TemporalUnit { + private Temporal temporal; + + FixedTemporalUnit(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalUnit"; + } + + @Override + public Duration getDuration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDurationEstimated() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSupported(Temporal temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doPlus(R dateTime, long periodToAdd) { + return (R) this.temporal; + } + + @Override + public SimplePeriod between(R dateTime1, R dateTime2) { + 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. + */ + static class FixedTemporalField implements TemporalField { + private Temporal temporal; + FixedTemporalField(Temporal temporal) { + this.temporal = temporal; + } + + @Override + public String getName() { + return "FixedTemporalField"; + } + + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange range() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @SuppressWarnings("unchecked") + @Override + public R doWith(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/TestISOChrono.java b/jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java new file mode 100644 index 00000000000..634fab301e5 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java @@ -0,0 +1,314 @@ +/* + * 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.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; +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.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 org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestISOChrono { + + //----------------------------------------------------------------------- + // Chrono.ofName("ISO") Lookup by name + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_chrono_byName() { + Chrono c = ISOChrono.INSTANCE; + Chrono test = Chrono.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"); + Assert.assertEquals(test, c); + } + + //----------------------------------------------------------------------- + // Lookup by Singleton + //----------------------------------------------------------------------- + @Test(groups="tck") + public void instanceNotNull() { + assertNotNull(ISOChrono.INSTANCE); + } + + //----------------------------------------------------------------------- + // Era creation + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_eraOf() { + assertEquals(ISOChrono.INSTANCE.eraOf(0), ERA_BCE); + assertEquals(ISOChrono.INSTANCE.eraOf(1), ERA_CE); + } + + //----------------------------------------------------------------------- + // creation, toLocalDate() + //----------------------------------------------------------------------- + @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)}, + + {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)}, + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_toLocalDate(ChronoLocalDate 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); + } + + @DataProvider(name="badDates") + Object[][] data_badDates() { + return new Object[][] { + {2012, 0, 0}, + + {2012, -1, 1}, + {2012, 0, 1}, + {2012, 14, 1}, + {2012, 15, 1}, + + {2012, 1, -1}, + {2012, 1, 0}, + {2012, 1, 32}, + + {2012, 12, -1}, + {2012, 12, 0}, + {2012, 12, 32}, + }; + } + + @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_badDates(int year, int month, int dom) { + ISOChrono.INSTANCE.date(year, month, dom); + } + + @Test(groups="tck") + public void test_date_withEra() { + int year = 5; + int month = 5; + int dayOfMonth = 5; + ChronoLocalDate test = ISOChrono.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); + assertEquals(test.get(ChronoField.DAY_OF_MONTH), dayOfMonth); + + assertEquals(test.get(YEAR), 1 + (-1 * year)); + assertEquals(test.get(ERA), 0); + assertEquals(test.get(YEAR_OF_ERA), year); + } + + @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); + } + + //----------------------------------------------------------------------- + // with(DateTimeAdjuster) + //----------------------------------------------------------------------- + @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)); + } + + @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)); + } + + //----------------------------------------------------------------------- + // ISODate.with(Local*) + //----------------------------------------------------------------------- + @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)); + } + + @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.with(ISODate) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_LocalDate_adjustToISODate() { + ChronoLocalDate isoDate = ISOChrono.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); + LocalDateTime test = LocalDateTime.MIN.with(isoDate); + assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0)); + } + + //----------------------------------------------------------------------- + // isLeapYear() + //----------------------------------------------------------------------- + @DataProvider(name="leapYears") + Object[][] leapYearInformation() { + return new Object[][] { + {2000, true}, + {1996, true}, + {1600, true}, + + {1900, false}, + {2100, false}, + }; + } + + @Test(dataProvider="leapYears", groups="tck") + public void test_isLeapYear(int year, boolean isLeapYear) { + assertEquals(ISOChrono.INSTANCE.isLeapYear(year), isLeapYear); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_now() { + assertEquals(LocalDate.from(ISOChrono.INSTANCE.dateNow()), LocalDate.now()); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @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"}, + }; + } + + @Test(dataProvider="toString", groups={"tck"}) + public void test_toString(ChronoLocalDate isoDate, String expected) { + assertEquals(isoDate.toString(), expected); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equals_true() { + assertTrue(ISOChrono.INSTANCE.equals(ISOChrono.INSTANCE)); + } + + @Test(groups="tck") + public void test_equals_false() { + assertFalse(ISOChrono.INSTANCE.equals(HijrahChrono.INSTANCE)); + } + +} diff --git a/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java new file mode 100644 index 00000000000..08617bae23b --- /dev/null +++ b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java @@ -0,0 +1,241 @@ +/* + * 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.zone; + +import java.time.zone.*; +import test.java.time.zone.*; + +import static org.testng.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ZoneRules for fixed offset time-zones. + */ +@Test +public class TCKFixedZoneRules { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_M18 = ZoneOffset.ofHours(-18); + private static final LocalDateTime LDT = LocalDateTime.of(2010, 12, 3, 11, 30); + private static final Instant INSTANT = LDT.toInstant(OFFSET_PONE); + + private ZoneRules make(ZoneOffset offset) { + return offset.getRules(); + } + + @DataProvider(name="rules") + Object[][] data_rules() { + return new Object[][] { + {make(OFFSET_PONE), OFFSET_PONE}, + {make(OFFSET_PTWO), OFFSET_PTWO}, + {make(OFFSET_M18), OFFSET_M18}, + }; + } + + //----------------------------------------------------------------------- + // Basics + //----------------------------------------------------------------------- + @Test(groups="tck", dataProvider="rules") + public void test_serialization(ZoneRules test, ZoneOffset expectedOffset) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(test); + baos.close(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bais); + ZoneRules result = (ZoneRules) in.readObject(); + + assertEquals(result, test); + assertEquals(result.getClass(), test.getClass()); + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + @Test(groups="tck", dataProvider="rules") + public void test_getOffset_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getOffset(INSTANT), expectedOffset); + assertEquals(test.getOffset((Instant) null), expectedOffset); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getOffset_LocalDateTime(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getOffset(LDT), expectedOffset); + assertEquals(test.getOffset((LocalDateTime) null), expectedOffset); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getValidOffsets_LDT(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getValidOffsets(LDT).size(), 1); + assertEquals(test.getValidOffsets(LDT).get(0), expectedOffset); + assertEquals(test.getValidOffsets(null).size(), 1); + assertEquals(test.getValidOffsets(null).get(0), expectedOffset); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getTransition_LDT(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getTransition(LDT), null); + assertEquals(test.getTransition(null), null); + } + + @Test(groups="tck", dataProvider="rules") + public void test_isValidOffset_LDT_ZO(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.isValidOffset(LDT, expectedOffset), true); + assertEquals(test.isValidOffset(LDT, ZoneOffset.UTC), false); + assertEquals(test.isValidOffset(LDT, null), false); + + assertEquals(test.isValidOffset(null, expectedOffset), true); + assertEquals(test.isValidOffset(null, ZoneOffset.UTC), false); + assertEquals(test.isValidOffset(null, null), false); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getStandardOffset_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getStandardOffset(INSTANT), expectedOffset); + assertEquals(test.getStandardOffset(null), expectedOffset); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getDaylightSavings_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getDaylightSavings(INSTANT), Duration.ZERO); + assertEquals(test.getDaylightSavings(null), Duration.ZERO); + } + + @Test(groups="tck", dataProvider="rules") + public void test_isDaylightSavings_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.isDaylightSavings(INSTANT), false); + assertEquals(test.isDaylightSavings(null), false); + } + + //------------------------------------------------------------------------- + @Test(groups="tck", dataProvider="rules") + public void test_nextTransition_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.nextTransition(INSTANT), null); + assertEquals(test.nextTransition(null), null); + } + + @Test(groups="tck", dataProvider="rules") + public void test_previousTransition_Instant(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.previousTransition(INSTANT), null); + assertEquals(test.previousTransition(null), null); + } + + //------------------------------------------------------------------------- + @Test(groups="tck", dataProvider="rules") + public void test_getTransitions(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getTransitions().size(), 0); + } + + @Test(expectedExceptions=UnsupportedOperationException.class, groups="tck") + public void test_getTransitions_immutable() { + ZoneRules test = make(OFFSET_PTWO); + test.getTransitions().add(ZoneOffsetTransition.of(LDT, OFFSET_PONE, OFFSET_PTWO)); + } + + @Test(groups="tck", dataProvider="rules") + public void test_getTransitionRules(ZoneRules test, ZoneOffset expectedOffset) { + assertEquals(test.getTransitionRules().size(), 0); + } + + @Test(expectedExceptions=UnsupportedOperationException.class, groups="tck") + public void test_getTransitionRules_immutable() { + ZoneRules test = make(OFFSET_PTWO); + test.getTransitionRules().add(ZoneOffsetTransitionRule.of(Month.JULY, 2, null, LocalTime.of(12, 30), false, TimeDefinition.STANDARD, OFFSET_PONE, OFFSET_PTWO, OFFSET_PONE)); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equalsHashCode() { + ZoneRules a = make(OFFSET_PONE); + ZoneRules b = make(OFFSET_PTWO); + + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + + assertEquals(a.equals("Rubbish"), false); + assertEquals(a.equals(null), false); + + assertEquals(a.hashCode() == a.hashCode(), true); + assertEquals(b.hashCode() == b.hashCode(), true); + } + +} diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java new file mode 100644 index 00000000000..36dc4ba0800 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.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.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 org.testng.annotations.Test; + +/** + * Test ZoneOffsetTransition. + */ +@Test +public class TCKZoneOffsetTransition extends AbstractTCKTest { + + private static final ZoneOffset OFFSET_0100 = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_0230 = ZoneOffset.ofHoursMinutes(2, 30); + private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3); + private static final ZoneOffset OFFSET_0400 = ZoneOffset.ofHours(4); + + //----------------------------------------------------------------------- + // factory + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullTransition() { + ZoneOffsetTransition.of(null, OFFSET_0100, OFFSET_0200); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullOffsetBefore() { + ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), null, OFFSET_0200); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullOffsetAfter() { + ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), OFFSET_0200, null); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_sameOffset() { + ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), OFFSET_0200, OFFSET_0200); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_noNanos() { + ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30, 0, 500), OFFSET_0200, OFFSET_0300); + } + + //----------------------------------------------------------------------- + // getters + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getters_gap() throws Exception { + LocalDateTime before = LocalDateTime.of(2010, 3, 31, 1, 0); + LocalDateTime after = LocalDateTime.of(2010, 3, 31, 2, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0200, OFFSET_0300); + assertEquals(test.isGap(), true); + assertEquals(test.isOverlap(), false); + assertEquals(test.getDateTimeBefore(), before); + assertEquals(test.getDateTimeAfter(), after); + assertEquals(test.getInstant(), before.toInstant(OFFSET_0200)); + assertEquals(test.getOffsetBefore(), OFFSET_0200); + assertEquals(test.getOffsetAfter(), OFFSET_0300); + assertEquals(test.getDuration(), Duration.of(1, HOURS)); + assertSerializable(test); + } + + @Test(groups={"tck"}) + public void test_getters_overlap() throws Exception { + LocalDateTime before = LocalDateTime.of(2010, 10, 31, 1, 0); + LocalDateTime after = LocalDateTime.of(2010, 10, 31, 0, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0300, OFFSET_0200); + assertEquals(test.isGap(), false); + assertEquals(test.isOverlap(), true); + assertEquals(test.getDateTimeBefore(), before); + assertEquals(test.getDateTimeAfter(), after); + assertEquals(test.getInstant(), before.toInstant(OFFSET_0300)); + assertEquals(test.getOffsetBefore(), OFFSET_0300); + assertEquals(test.getOffsetAfter(), OFFSET_0200); + assertEquals(test.getDuration(), Duration.of(-1, HOURS)); + assertSerializable(test); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization_unusual1() throws Exception { + LocalDateTime ldt = LocalDateTime.of(Year.MAX_VALUE, 12, 31, 1, 31, 53); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("-10:02:34")); + assertSerializable(test); + } + + @Test + public void test_serialization_unusual2() throws Exception { + LocalDateTime ldt = LocalDateTime.of(Year.MIN_VALUE, 1, 1, 12, 1, 3); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("+10:02:34")); + assertSerializable(test); + } + + //----------------------------------------------------------------------- + // isValidOffset() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_isValidOffset_gap() { + LocalDateTime ldt = LocalDateTime.of(2010, 3, 31, 1, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0200, OFFSET_0300); + assertEquals(test.isValidOffset(OFFSET_0100), false); + assertEquals(test.isValidOffset(OFFSET_0200), false); + assertEquals(test.isValidOffset(OFFSET_0230), false); + assertEquals(test.isValidOffset(OFFSET_0300), false); + assertEquals(test.isValidOffset(OFFSET_0400), false); + } + + @Test(groups={"tck"}) + public void test_isValidOffset_overlap() { + LocalDateTime ldt = LocalDateTime.of(2010, 10, 31, 1, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0300, OFFSET_0200); + assertEquals(test.isValidOffset(OFFSET_0100), false); + assertEquals(test.isValidOffset(OFFSET_0200), true); + assertEquals(test.isValidOffset(OFFSET_0230), false); + assertEquals(test.isValidOffset(OFFSET_0300), true); + assertEquals(test.isValidOffset(OFFSET_0400), false); + } + + //----------------------------------------------------------------------- + // compareTo() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_compareTo() { + ZoneOffsetTransition a = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L - 1, 0, OFFSET_0200), OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition b = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0300), OFFSET_0300, OFFSET_0200); + ZoneOffsetTransition c = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L + 1, 0, OFFSET_0100), OFFSET_0100,OFFSET_0400); + + assertEquals(a.compareTo(a) == 0, true); + assertEquals(a.compareTo(b) < 0, true); + assertEquals(a.compareTo(c) < 0, true); + + assertEquals(b.compareTo(a) > 0, true); + assertEquals(b.compareTo(b) == 0, true); + assertEquals(b.compareTo(c) < 0, true); + + assertEquals(c.compareTo(a) > 0, true); + assertEquals(c.compareTo(b) > 0, true); + assertEquals(c.compareTo(c) == 0, true); + } + + @Test(groups={"tck"}) + public void test_compareTo_sameInstant() { + ZoneOffsetTransition a = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0200), OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition b = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0300), OFFSET_0300, OFFSET_0200); + ZoneOffsetTransition c = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0100), OFFSET_0100, OFFSET_0400); + + assertEquals(a.compareTo(a) == 0, true); + assertEquals(a.compareTo(b) == 0, true); + assertEquals(a.compareTo(c) == 0, true); + + assertEquals(b.compareTo(a) == 0, true); + assertEquals(b.compareTo(b) == 0, true); + assertEquals(b.compareTo(c) == 0, true); + + assertEquals(c.compareTo(a) == 0, true); + assertEquals(c.compareTo(b) == 0, true); + assertEquals(c.compareTo(c) == 0, true); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals() { + LocalDateTime ldtA = LocalDateTime.of(2010, 3, 31, 1, 0); + ZoneOffsetTransition a1 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition a2 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300); + LocalDateTime ldtB = LocalDateTime.of(2010, 10, 31, 1, 0); + ZoneOffsetTransition b = ZoneOffsetTransition.of(ldtB, OFFSET_0300, OFFSET_0200); + + assertEquals(a1.equals(a1), true); + assertEquals(a1.equals(a2), true); + assertEquals(a1.equals(b), false); + assertEquals(a2.equals(a1), true); + assertEquals(a2.equals(a2), true); + assertEquals(a2.equals(b), false); + assertEquals(b.equals(a1), false); + assertEquals(b.equals(a2), false); + assertEquals(b.equals(b), true); + + assertEquals(a1.equals(""), false); + assertEquals(a1.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_hashCode_floatingWeek_gap_notEndOfDay() { + LocalDateTime ldtA = LocalDateTime.of(2010, 3, 31, 1, 0); + ZoneOffsetTransition a1 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition a2 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300); + LocalDateTime ldtB = LocalDateTime.of(2010, 10, 31, 1, 0); + ZoneOffsetTransition b = ZoneOffsetTransition.of(ldtB, OFFSET_0300, OFFSET_0200); + + assertEquals(a1.hashCode(), a1.hashCode()); + assertEquals(a1.hashCode(), a2.hashCode()); + assertEquals(b.hashCode(), b.hashCode()); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_gap() { + LocalDateTime ldt = LocalDateTime.of(2010, 3, 31, 1, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0200, OFFSET_0300); + assertEquals(test.toString(), "Transition[Gap at 2010-03-31T01:00+02:00 to +03:00]"); + } + + @Test(groups={"tck"}) + public void test_toString_overlap() { + LocalDateTime ldt = LocalDateTime.of(2010, 10, 31, 1, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0300, OFFSET_0200); + assertEquals(test.toString(), "Transition[Overlap at 2010-10-31T01:00+03:00 to +02:00]"); + } + +} diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java new file mode 100644 index 00000000000..f98d7141b16 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java @@ -0,0 +1,557 @@ +/* + * 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.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.ZoneOffsetTransitionRule.TimeDefinition; + +import org.testng.annotations.Test; + +/** + * Test ZoneOffsetTransitionRule. + */ +@Test +public class TCKZoneOffsetTransitionRule extends AbstractTCKTest { + + private static final LocalTime TIME_0100 = LocalTime.of(1, 0); + private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3); + + //----------------------------------------------------------------------- + // factory + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullMonth() { + ZoneOffsetTransitionRule.of( + null, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullTime() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, null, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullTimeDefinition() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, null, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullStandardOffset() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + null, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullOffsetBefore() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, null, OFFSET_0300); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_factory_nullOffsetAfter() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, null); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_invalidDayOfMonthIndicator_tooSmall() { + ZoneOffsetTransitionRule.of( + Month.MARCH, -29, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_invalidDayOfMonthIndicator_zero() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 0, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_invalidDayOfMonthIndicator_tooLarge() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 32, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + public void test_factory_invalidMidnightFlag() { + ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + } + + //----------------------------------------------------------------------- + // getters + //----------------------------------------------------------------------- + @Test + public void test_getters_floatingWeek() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.getMonth(), Month.MARCH); + assertEquals(test.getDayOfMonthIndicator(), 20); + assertEquals(test.getDayOfWeek(), DayOfWeek.SUNDAY); + assertEquals(test.getLocalTime(), TIME_0100); + assertEquals(test.isMidnightEndOfDay(), false); + assertEquals(test.getTimeDefinition(), TimeDefinition.WALL); + assertEquals(test.getStandardOffset(), OFFSET_0200); + assertEquals(test.getOffsetBefore(), OFFSET_0200); + assertEquals(test.getOffsetAfter(), OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_getters_floatingWeekBackwards() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.getMonth(), Month.MARCH); + assertEquals(test.getDayOfMonthIndicator(), -1); + assertEquals(test.getDayOfWeek(), DayOfWeek.SUNDAY); + assertEquals(test.getLocalTime(), TIME_0100); + assertEquals(test.isMidnightEndOfDay(), false); + assertEquals(test.getTimeDefinition(), TimeDefinition.WALL); + assertEquals(test.getStandardOffset(), OFFSET_0200); + assertEquals(test.getOffsetBefore(), OFFSET_0200); + assertEquals(test.getOffsetAfter(), OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_getters_fixedDate() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.getMonth(), Month.MARCH); + assertEquals(test.getDayOfMonthIndicator(), 20); + assertEquals(test.getDayOfWeek(), null); + assertEquals(test.getLocalTime(), TIME_0100); + assertEquals(test.isMidnightEndOfDay(), false); + assertEquals(test.getTimeDefinition(), TimeDefinition.WALL); + assertEquals(test.getStandardOffset(), OFFSET_0200); + assertEquals(test.getOffsetBefore(), OFFSET_0200); + assertEquals(test.getOffsetAfter(), OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_unusualOffsets() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + ZoneOffset.ofHoursMinutesSeconds(-12, -20, -50), + ZoneOffset.ofHoursMinutesSeconds(-4, -10, -34), + ZoneOffset.ofHours(-18)); + assertSerializable(test); + } + + @Test + public void test_serialization_endOfDay() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.FRIDAY, LocalTime.MIDNIGHT, true, TimeDefinition.UTC, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_unusualTime() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.WEDNESDAY, LocalTime.of(13, 34, 56), false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + //----------------------------------------------------------------------- + // createTransition() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_createTransition_floatingWeek_gap_notEndOfDay() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300); + assertEquals(test.createTransition(2000), trans); + } + + @Test(groups={"tck"}) + public void test_createTransition_floatingWeek_overlap_endOfDay() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0300, OFFSET_0200); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 27, 0, 0), OFFSET_0300, OFFSET_0200); + assertEquals(test.createTransition(2000), trans); + } + + @Test(groups={"tck"}) + public void test_createTransition_floatingWeekBackwards_last() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300); + assertEquals(test.createTransition(2000), trans); + } + + @Test(groups={"tck"}) + public void test_createTransition_floatingWeekBackwards_seventhLast() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -7, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 19, 1, 0), OFFSET_0200, OFFSET_0300); + assertEquals(test.createTransition(2000), trans); + } + + @Test(groups={"tck"}) + public void test_createTransition_floatingWeekBackwards_secondLast() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -2, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300); + assertEquals(test.createTransition(2000), trans); + } + + @Test(groups={"tck"}) + public void test_createTransition_fixedDate() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.of(2000, Month.MARCH, 20, 1, 0), OFFSET_0200, OFFSET_0300); + assertEquals(test.createTransition(2000), trans); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_equals_monthDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.APRIL, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_dayOfMonthDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 21, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_dayOfWeekDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SATURDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_dayOfWeekDifferentNull() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_localTimeDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_endOfDayDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_timeDefinitionDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_standardOffsetDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0300, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_offsetBeforeDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0300, OFFSET_0300); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_offsetAfterDifferent() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0200); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(b.equals(b), true); + } + + @Test(groups={"tck"}) + public void test_equals_string_false() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals("TZDB"), false); + } + + @Test(groups={"tck"}) + public void test_equals_null_false() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.equals(null), false); + } + + //----------------------------------------------------------------------- + // hashCode() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_hashCode_floatingWeek_gap_notEndOfDay() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_hashCode_floatingWeek_overlap_endOfDay_nullDayOfWeek() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.OCTOBER, 20, null, LocalTime.MIDNIGHT, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0300, OFFSET_0200); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.OCTOBER, 20, null, LocalTime.MIDNIGHT, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0300, OFFSET_0200); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_hashCode_floatingWeekBackwards() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test(groups={"tck"}) + public void test_hashCode_fixedDate() { + ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(a.hashCode(), b.hashCode()); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_toString_floatingWeek_gap_notEndOfDay() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or after MARCH 20 at 01:00 WALL, standard offset +02:00]"); + } + + @Test(groups={"tck"}) + public void test_toString_floatingWeek_overlap_endOfDay() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.OCTOBER, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0300, OFFSET_0200); + assertEquals(test.toString(), "TransitionRule[Overlap +03:00 to +02:00, SUNDAY on or after OCTOBER 20 at 24:00 WALL, standard offset +02:00]"); + } + + @Test(groups={"tck"}) + public void test_toString_floatingWeekBackwards_last() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or before last day of MARCH at 01:00 WALL, standard offset +02:00]"); + } + + @Test(groups={"tck"}) + public void test_toString_floatingWeekBackwards_secondLast() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -2, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or before last day minus 1 of MARCH at 01:00 WALL, standard offset +02:00]"); + } + + @Test(groups={"tck"}) + public void test_toString_fixedDate() { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, MARCH 20 at 01:00 STANDARD, standard offset +02:00]"); + } + +} diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java new file mode 100644 index 00000000000..294e2e07cb2 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java @@ -0,0 +1,1005 @@ +/* + * 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.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; +import static org.testng.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Iterator; +import java.util.List; + +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; + +import org.testng.annotations.Test; + +/** + * Test ZoneRules. + */ +@Test +public class TCKZoneRules { + + private static final ZoneOffset OFFSET_ZERO = ZoneOffset.ofHours(0); + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + public static final String LATEST_TZDB = "2009b"; + private static final int OVERLAP = 2; + private static final int GAP = 0; + + //----------------------------------------------------------------------- + // Basics + //----------------------------------------------------------------------- + public void test_serialization_loaded() throws Exception { + assertSerialization(europeLondon()); + assertSerialization(europeParis()); + assertSerialization(americaNewYork()); + } + + private void assertSerialization(ZoneRules test) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(test); + baos.close(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bais); + ZoneRules result = (ZoneRules) in.readObject(); + + assertEquals(result, test); + } + + //----------------------------------------------------------------------- + // Europe/London + //----------------------------------------------------------------------- + private ZoneRules europeLondon() { + return ZoneId.of("Europe/London").getRules(); + } + + public void test_London() { + ZoneRules test = europeLondon(); + assertEquals(test.isFixedOffset(), false); + } + + public void test_London_preTimeZones() { + ZoneRules test = europeLondon(); + ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC); + Instant instant = old.toInstant(); + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, -1, -15); + assertEquals(test.getOffset(instant), offset); + checkOffset(test, old.getDateTime(), offset, 1); + assertEquals(test.getStandardOffset(instant), offset); + assertEquals(test.getDaylightSavings(instant), Duration.ZERO); + assertEquals(test.isDaylightSavings(instant), false); + } + + public void test_London_getOffset() { + ZoneRules test = europeLondon(); + assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_ZERO); + } + + public void test_London_getOffset_toDST() { + ZoneRules test = europeLondon(); + assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PONE); + // cutover at 01:00Z + assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE); + } + + public void test_London_getOffset_fromDST() { + ZoneRules test = europeLondon(); + assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_ZERO); + assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_ZERO); + // cutover at 01:00Z + assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_ZERO); + } + + public void test_London_getOffsetInfo() { + ZoneRules test = europeLondon(); + checkOffset(test, createLDT(2008, 1, 1), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 2, 1), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 1), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 4, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 5, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 6, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 7, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 8, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 9, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 11, 1), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 12, 1), OFFSET_ZERO, 1); + } + + public void test_London_getOffsetInfo_toDST() { + ZoneRules test = europeLondon(); + checkOffset(test, createLDT(2008, 3, 24), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 25), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 26), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 27), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 28), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 29), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 30), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 3, 31), OFFSET_PONE, 1); + // cutover at 01:00Z + checkOffset(test, LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), OFFSET_ZERO, 1); + checkOffset(test, LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), OFFSET_PONE, 1); + } + + public void test_London_getOffsetInfo_fromDST() { + ZoneRules test = europeLondon(); + checkOffset(test, createLDT(2008, 10, 24), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 25), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 26), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 27), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 10, 28), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 10, 29), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 10, 30), OFFSET_ZERO, 1); + checkOffset(test, createLDT(2008, 10, 31), OFFSET_ZERO, 1); + // cutover at 01:00Z + checkOffset(test, LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), OFFSET_PONE, 1); + checkOffset(test, LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), OFFSET_ZERO, 1); + } + + public void test_London_getOffsetInfo_gap() { + ZoneRules test = europeLondon(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_ZERO, GAP); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.getOffsetBefore(), OFFSET_ZERO); + assertEquals(trans.getOffsetAfter(), OFFSET_PONE); + assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC)); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0)); + assertEquals(trans.isValidOffset(OFFSET_ZERO), false); + assertEquals(trans.isValidOffset(OFFSET_PONE), false); + assertEquals(trans.isValidOffset(OFFSET_PTWO), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(OFFSET_ZERO)); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_London_getOffsetInfo_overlap() { + ZoneRules test = europeLondon(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, OVERLAP); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.getOffsetBefore(), OFFSET_PONE); + assertEquals(trans.getOffsetAfter(), OFFSET_ZERO); + assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC)); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0)); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false); + assertEquals(trans.isValidOffset(OFFSET_ZERO), true); + assertEquals(trans.isValidOffset(OFFSET_PONE), true); + assertEquals(trans.isValidOffset(OFFSET_PTWO), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(OFFSET_PONE)); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_London_getStandardOffset() { + ZoneRules test = europeLondon(); + ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC); + while (zdt.getYear() < 2010) { + Instant instant = zdt.toInstant(); + if (zdt.getYear() < 1848) { + assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15)); + } else if (zdt.getYear() >= 1969 && zdt.getYear() < 1972) { + assertEquals(test.getStandardOffset(instant), OFFSET_PONE); + } else { + assertEquals(test.getStandardOffset(instant), OFFSET_ZERO); + } + zdt = zdt.plusMonths(6); + } + } + + public void test_London_getTransitions() { + ZoneRules test = europeLondon(); + List trans = test.getTransitions(); + + ZoneOffsetTransition first = trans.get(0); + assertEquals(first.getDateTimeBefore(), LocalDateTime.of(1847, 12, 1, 0, 0)); + assertEquals(first.getOffsetBefore(), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15)); + assertEquals(first.getOffsetAfter(), OFFSET_ZERO); + + ZoneOffsetTransition spring1916 = trans.get(1); + assertEquals(spring1916.getDateTimeBefore(), LocalDateTime.of(1916, 5, 21, 2, 0)); + assertEquals(spring1916.getOffsetBefore(), OFFSET_ZERO); + assertEquals(spring1916.getOffsetAfter(), OFFSET_PONE); + + ZoneOffsetTransition autumn1916 = trans.get(2); + assertEquals(autumn1916.getDateTimeBefore(), LocalDateTime.of(1916, 10, 1, 3, 0)); + assertEquals(autumn1916.getOffsetBefore(), OFFSET_PONE); + assertEquals(autumn1916.getOffsetAfter(), OFFSET_ZERO); + + ZoneOffsetTransition zot = null; + Iterator it = trans.iterator(); + while (it.hasNext()) { + zot = it.next(); + if (zot.getDateTimeBefore().getYear() == 1990) { + break; + } + } + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 3, 25, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 10, 28, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 3, 31, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 10, 27, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 3, 29, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 10, 25, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 3, 28, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 10, 24, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 3, 27, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 10, 23, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 3, 26, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 10, 22, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 3, 31, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 10, 27, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 3, 30, 1, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_ZERO); + zot = it.next(); + assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 10, 26, 2, 0)); + assertEquals(zot.getOffsetBefore(), OFFSET_PONE); + assertEquals(it.hasNext(), false); + } + + public void test_London_getTransitionRules() { + ZoneRules test = europeLondon(); + List rules = test.getTransitionRules(); + assertEquals(rules.size(), 2); + + ZoneOffsetTransitionRule in = rules.get(0); + assertEquals(in.getMonth(), Month.MARCH); + assertEquals(in.getDayOfMonthIndicator(), 25); // optimized from -1 + assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY); + assertEquals(in.getLocalTime(), LocalTime.of(1, 0)); + assertEquals(in.getTimeDefinition(), TimeDefinition.UTC); + assertEquals(in.getStandardOffset(), OFFSET_ZERO); + assertEquals(in.getOffsetBefore(), OFFSET_ZERO); + assertEquals(in.getOffsetAfter(), OFFSET_PONE); + + ZoneOffsetTransitionRule out = rules.get(1); + assertEquals(out.getMonth(), Month.OCTOBER); + assertEquals(out.getDayOfMonthIndicator(), 25); // optimized from -1 + assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY); + assertEquals(out.getLocalTime(), LocalTime.of(1, 0)); + assertEquals(out.getTimeDefinition(), TimeDefinition.UTC); + assertEquals(out.getStandardOffset(), OFFSET_ZERO); + assertEquals(out.getOffsetBefore(), OFFSET_PONE); + assertEquals(out.getOffsetAfter(), OFFSET_ZERO); + } + + //----------------------------------------------------------------------- + public void test_London_nextTransition_historic() { + ZoneRules test = europeLondon(); + List trans = test.getTransitions(); + + ZoneOffsetTransition first = trans.get(0); + assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first); + + for (int i = 0; i < trans.size() - 1; i++) { + ZoneOffsetTransition cur = trans.get(i); + ZoneOffsetTransition next = trans.get(i + 1); + + assertEquals(test.nextTransition(cur.getInstant()), next); + assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next); + } + } + + public void test_London_nextTransition_rulesBased() { + ZoneRules test = europeLondon(); + List rules = test.getTransitionRules(); + List trans = test.getTransitions(); + + ZoneOffsetTransition last = trans.get(trans.size() - 1); + assertEquals(test.nextTransition(last.getInstant()), rules.get(0).createTransition(1998)); + + for (int year = 1998; year < 2010; year++) { + ZoneOffsetTransition a = rules.get(0).createTransition(year); + ZoneOffsetTransition b = rules.get(1).createTransition(year); + ZoneOffsetTransition c = rules.get(0).createTransition(year + 1); + + assertEquals(test.nextTransition(a.getInstant()), b); + assertEquals(test.nextTransition(b.getInstant().minusNanos(1)), b); + + assertEquals(test.nextTransition(b.getInstant()), c); + assertEquals(test.nextTransition(c.getInstant().minusNanos(1)), c); + } + } + + public void test_London_nextTransition_lastYear() { + ZoneRules test = europeLondon(); + List rules = test.getTransitionRules(); + ZoneOffsetTransition zot = rules.get(1).createTransition(Year.MAX_VALUE); + assertEquals(test.nextTransition(zot.getInstant()), null); + } + + //----------------------------------------------------------------------- + public void test_London_previousTransition_historic() { + ZoneRules test = europeLondon(); + List trans = test.getTransitions(); + + ZoneOffsetTransition first = trans.get(0); + assertEquals(test.previousTransition(first.getInstant()), null); + assertEquals(test.previousTransition(first.getInstant().minusNanos(1)), null); + + for (int i = 0; i < trans.size() - 1; i++) { + ZoneOffsetTransition prev = trans.get(i); + ZoneOffsetTransition cur = trans.get(i + 1); + + assertEquals(test.previousTransition(cur.getInstant()), prev); + assertEquals(test.previousTransition(prev.getInstant().plusSeconds(1)), prev); + assertEquals(test.previousTransition(prev.getInstant().plusNanos(1)), prev); + } + } + + public void test_London_previousTransition_rulesBased() { + ZoneRules test = europeLondon(); + List rules = test.getTransitionRules(); + List trans = test.getTransitions(); + + ZoneOffsetTransition last = trans.get(trans.size() - 1); + assertEquals(test.previousTransition(last.getInstant().plusSeconds(1)), last); + assertEquals(test.previousTransition(last.getInstant().plusNanos(1)), last); + + // Jan 1st of year between transitions and rules + ZonedDateTime odt = ZonedDateTime.ofInstant(last.getInstant(), last.getOffsetAfter()); + odt = odt.withDayOfYear(1).plusYears(1).with(LocalTime.MIDNIGHT); + assertEquals(test.previousTransition(odt.toInstant()), last); + + // later years + for (int year = 1998; year < 2010; year++) { + ZoneOffsetTransition a = rules.get(0).createTransition(year); + ZoneOffsetTransition b = rules.get(1).createTransition(year); + ZoneOffsetTransition c = rules.get(0).createTransition(year + 1); + + assertEquals(test.previousTransition(c.getInstant()), b); + assertEquals(test.previousTransition(b.getInstant().plusSeconds(1)), b); + assertEquals(test.previousTransition(b.getInstant().plusNanos(1)), b); + + assertEquals(test.previousTransition(b.getInstant()), a); + assertEquals(test.previousTransition(a.getInstant().plusSeconds(1)), a); + assertEquals(test.previousTransition(a.getInstant().plusNanos(1)), a); + } + } + + //----------------------------------------------------------------------- + // Europe/Paris + //----------------------------------------------------------------------- + private ZoneRules europeParis() { + return ZoneId.of("Europe/Paris").getRules(); + } + + public void test_Paris() { + ZoneRules test = europeParis(); + assertEquals(test.isFixedOffset(), false); + } + + public void test_Paris_preTimeZones() { + ZoneRules test = europeParis(); + ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC); + Instant instant = old.toInstant(); + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21); + assertEquals(test.getOffset(instant), offset); + checkOffset(test, old.getDateTime(), offset, 1); + assertEquals(test.getStandardOffset(instant), offset); + assertEquals(test.getDaylightSavings(instant), Duration.ZERO); + assertEquals(test.isDaylightSavings(instant), false); + } + + public void test_Paris_getOffset() { + ZoneRules test = europeParis(); + assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_PONE); + } + + public void test_Paris_getOffset_toDST() { + ZoneRules test = europeParis(); + assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PTWO); + // cutover at 01:00Z + assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PTWO); + } + + public void test_Paris_getOffset_fromDST() { + ZoneRules test = europeParis(); + assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_PONE); + assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_PONE); + // cutover at 01:00Z + assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PTWO); + assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE); + } + + public void test_Paris_getOffsetInfo() { + ZoneRules test = europeParis(); + checkOffset(test, createLDT(2008, 1, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 2, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 4, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 5, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 6, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 7, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 8, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 9, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 10, 1), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 11, 1), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 12, 1), OFFSET_PONE, 1); + } + + public void test_Paris_getOffsetInfo_toDST() { + ZoneRules test = europeParis(); + checkOffset(test, createLDT(2008, 3, 24), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 25), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 26), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 27), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 28), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 29), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 30), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 3, 31), OFFSET_PTWO, 1); + // cutover at 01:00Z which is 02:00+01:00(local Paris time) + checkOffset(test, LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), OFFSET_PONE, 1); + checkOffset(test, LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), OFFSET_PTWO, 1); + } + + public void test_Paris_getOffsetInfo_fromDST() { + ZoneRules test = europeParis(); + checkOffset(test, createLDT(2008, 10, 24), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 10, 25), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 10, 26), OFFSET_PTWO, 1); + checkOffset(test, createLDT(2008, 10, 27), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 28), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 29), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 30), OFFSET_PONE, 1); + checkOffset(test, createLDT(2008, 10, 31), OFFSET_PONE, 1); + // cutover at 01:00Z which is 02:00+01:00(local Paris time) + checkOffset(test, LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), OFFSET_PTWO, 1); + checkOffset(test, LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), OFFSET_PONE, 1); + } + + public void test_Paris_getOffsetInfo_gap() { + ZoneRules test = europeParis(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, GAP); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.getOffsetBefore(), OFFSET_PONE); + assertEquals(trans.getOffsetAfter(), OFFSET_PTWO); + assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC)); + assertEquals(trans.isValidOffset(OFFSET_ZERO), false); + assertEquals(trans.isValidOffset(OFFSET_PONE), false); + assertEquals(trans.isValidOffset(OFFSET_PTWO), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(OFFSET_PONE)); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_Paris_getOffsetInfo_overlap() { + ZoneRules test = europeParis(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PTWO, OVERLAP); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.getOffsetBefore(), OFFSET_PTWO); + assertEquals(trans.getOffsetAfter(), OFFSET_PONE); + assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC)); + assertEquals(trans.isValidOffset(OFFSET_ZERO), false); + assertEquals(trans.isValidOffset(OFFSET_PONE), true); + assertEquals(trans.isValidOffset(OFFSET_PTWO), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(OFFSET_PTWO)); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_Paris_getStandardOffset() { + ZoneRules test = europeParis(); + 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))) { + assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21)); + } else if (zdt.getDate().isBefore(LocalDate.of(1940, 6, 14))) { + assertEquals(test.getStandardOffset(instant), OFFSET_ZERO); + } else if (zdt.getDate().isBefore(LocalDate.of(1944, 8, 25))) { + assertEquals(test.getStandardOffset(instant), OFFSET_PONE); + } else if (zdt.getDate().isBefore(LocalDate.of(1945, 9, 16))) { + assertEquals(test.getStandardOffset(instant), OFFSET_ZERO); + } else { + assertEquals(test.getStandardOffset(instant), OFFSET_PONE); + } + zdt = zdt.plusMonths(6); + } + } + + //----------------------------------------------------------------------- + // America/New_York + //----------------------------------------------------------------------- + private ZoneRules americaNewYork() { + return ZoneId.of("America/New_York").getRules(); + } + + public void test_NewYork() { + ZoneRules test = americaNewYork(); + assertEquals(test.isFixedOffset(), false); + } + + public void test_NewYork_preTimeZones() { + ZoneRules test = americaNewYork(); + ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC); + Instant instant = old.toInstant(); + ZoneOffset offset = ZoneOffset.of("-04:56:02"); + assertEquals(test.getOffset(instant), offset); + checkOffset(test, old.getDateTime(), offset, 1); + assertEquals(test.getStandardOffset(instant), offset); + assertEquals(test.getDaylightSavings(instant), Duration.ZERO); + assertEquals(test.isDaylightSavings(instant), false); + } + + public void test_NewYork_getOffset() { + ZoneRules test = americaNewYork(); + ZoneOffset offset = ZoneOffset.ofHours(-5); + assertEquals(test.getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5)); + } + + public void test_NewYork_getOffset_toDST() { + ZoneRules test = americaNewYork(); + ZoneOffset offset = ZoneOffset.ofHours(-5); + assertEquals(test.getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4)); + // cutover at 02:00 local + assertEquals(test.getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4)); + } + + public void test_NewYork_getOffset_fromDST() { + ZoneRules test = americaNewYork(); + ZoneOffset offset = ZoneOffset.ofHours(-4); + assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5)); + // cutover at 02:00 local + assertEquals(test.getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5)); + } + + public void test_NewYork_getOffsetInfo() { + ZoneRules test = americaNewYork(); + checkOffset(test, createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1); + } + + public void test_NewYork_getOffsetInfo_toDST() { + ZoneRules test = americaNewYork(); + checkOffset(test, createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1); + // cutover at 02:00 local + checkOffset(test, LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1); + checkOffset(test, LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1); + } + + public void test_NewYork_getOffsetInfo_fromDST() { + ZoneRules test = americaNewYork(); + checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1); + checkOffset(test, createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1); + checkOffset(test, createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1); + // cutover at 02:00 local + checkOffset(test, LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1); + checkOffset(test, LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1); + } + + public void test_NewYork_getOffsetInfo_gap() { + ZoneRules test = americaNewYork(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-5), GAP); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4)); + assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, ZoneOffset.ofHours(-5))); + assertEquals(trans.isValidOffset(OFFSET_PTWO), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(-5))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_NewYork_getOffsetInfo_overlap() { + ZoneRules test = americaNewYork(); + final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-4), OVERLAP); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5)); + assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, ZoneOffset.ofHours(-4))); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true); + assertEquals(trans.isValidOffset(OFFSET_PTWO), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(-4))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_NewYork_getStandardOffset() { + ZoneRules test = americaNewYork(); + 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))) { + assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02")); + } else { + assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5)); + } + dateTime = dateTime.plusMonths(6); + } + } + + //----------------------------------------------------------------------- + // Kathmandu + //----------------------------------------------------------------------- + private ZoneRules asiaKathmandu() { + return ZoneId.of("Asia/Kathmandu").getRules(); + } + + public void test_Kathmandu_nextTransition_historic() { + ZoneRules test = asiaKathmandu(); + List trans = test.getTransitions(); + + ZoneOffsetTransition first = trans.get(0); + assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first); + + for (int i = 0; i < trans.size() - 1; i++) { + ZoneOffsetTransition cur = trans.get(i); + ZoneOffsetTransition next = trans.get(i + 1); + + assertEquals(test.nextTransition(cur.getInstant()), next); + assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next); + } + } + + public void test_Kathmandu_nextTransition_noRules() { + ZoneRules test = asiaKathmandu(); + List trans = test.getTransitions(); + + ZoneOffsetTransition last = trans.get(trans.size() - 1); + assertEquals(test.nextTransition(last.getInstant()), null); + } + + //------------------------------------------------------------------------- + @Test(expectedExceptions=UnsupportedOperationException.class) + public void test_getTransitions_immutable() { + ZoneRules test = europeParis(); + test.getTransitions().clear(); + } + + @Test(expectedExceptions=UnsupportedOperationException.class) + public void test_getTransitionRules_immutable() { + ZoneRules test = europeParis(); + test.getTransitionRules().clear(); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + public void test_equals() { + ZoneRules test1 = europeLondon(); + ZoneRules test2 = europeParis(); + ZoneRules test2b = europeParis(); + 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(europeLondon().equals(null), false); + } + + public void test_equals_notZoneRules() { + assertEquals(europeLondon().equals("Europe/London"), false); + } + + public void test_toString() { + assertEquals(europeLondon().toString().contains("ZoneRules"), true); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + private Instant createInstant(int year, int month, int day, ZoneOffset offset) { + return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset); + } + + private Instant createInstant(int year, int month, int day, int hour, int min, ZoneOffset offset) { + return LocalDateTime.of(year, month, day, hour, min).toInstant(offset); + } + + private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) { + return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset); + } + + private ZonedDateTime createZDT(int year, int month, int day, ZoneId zone) { + return LocalDateTime.of(year, month, day, 0, 0).atZone(zone); + } + + private LocalDateTime createLDT(int year, int month, int day) { + return LocalDateTime.of(year, month, day, 0, 0); + } + + private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) { + List validOffsets = rules.getValidOffsets(dateTime); + assertEquals(validOffsets.size(), type); + assertEquals(rules.getOffset(dateTime), offset); + if (type == 1) { + assertEquals(validOffsets.get(0), offset); + return null; + } else { + ZoneOffsetTransition zot = rules.getTransition(dateTime); + assertNotNull(zot); + assertEquals(zot.isOverlap(), type == 2); + assertEquals(zot.isGap(), type == 0); + assertEquals(zot.isValidOffset(offset), type == 2); + return zot; + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java new file mode 100644 index 00000000000..2d245f66115 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java @@ -0,0 +1,196 @@ +/* + * 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 tck.java.time.zone; + +import java.time.zone.*; +import test.java.time.zone.*; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Collections; +import java.util.HashSet; +import java.util.NavigableMap; +import java.util.Set; +import java.util.TreeMap; + +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test ZoneRulesProvider. + */ +@Test +public class TCKZoneRulesProvider { + + private static String TZDB_VERSION = "2012i"; + + //----------------------------------------------------------------------- + // getAvailableZoneIds() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getAvailableGroupIds() { + Set zoneIds = ZoneRulesProvider.getAvailableZoneIds(); + assertEquals(zoneIds.contains("Europe/London"), true); + zoneIds.clear(); + assertEquals(zoneIds.size(), 0); + Set zoneIds2 = ZoneRulesProvider.getAvailableZoneIds(); + assertEquals(zoneIds2.contains("Europe/London"), true); + } + + //----------------------------------------------------------------------- + // getRules(String) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getRules_String() { + ZoneRules rules = ZoneRulesProvider.getRules("Europe/London"); + assertNotNull(rules); + ZoneRules rules2 = ZoneRulesProvider.getRules("Europe/London"); + assertEquals(rules2, rules); + } + + @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class) + public void test_getRules_String_unknownId() { + ZoneRulesProvider.getRules("Europe/Lon"); + } + + @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + public void test_getRules_String_null() { + ZoneRulesProvider.getRules(null); + } + + //----------------------------------------------------------------------- + // getVersions(String) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_getVersions_String() { + NavigableMap versions = ZoneRulesProvider.getVersions("Europe/London"); + assertTrue(versions.size() >= 1); + ZoneRules rules = ZoneRulesProvider.getRules("Europe/London"); + assertEquals(versions.lastEntry().getValue(), rules); + + NavigableMap copy = new TreeMap<>(versions); + versions.clear(); + assertEquals(versions.size(), 0); + NavigableMap versions2 = ZoneRulesProvider.getVersions("Europe/London"); + assertEquals(versions2, copy); + } + + @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class) + public void test_getVersions_String_unknownId() { + ZoneRulesProvider.getVersions("Europe/Lon"); + } + + @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + public void test_getVersions_String_null() { + ZoneRulesProvider.getVersions(null); + } + + //----------------------------------------------------------------------- + // refresh() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_refresh() { + assertEquals(ZoneRulesProvider.refresh(), false); + } + + //----------------------------------------------------------------------- + // registerProvider() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_registerProvider() { + Set pre = ZoneRulesProvider.getAvailableZoneIds(); + assertEquals(pre.contains("FooLocation"), false); + ZoneRulesProvider.registerProvider(new MockTempProvider()); + assertEquals(pre.contains("FooLocation"), false); + Set post = ZoneRulesProvider.getAvailableZoneIds(); + assertEquals(post.contains("FooLocation"), true); + + assertEquals(ZoneRulesProvider.getRules("FooLocation"), ZoneOffset.of("+01:45").getRules()); + } + + static class MockTempProvider extends ZoneRulesProvider { + final ZoneRules rules = ZoneOffset.of("+01:45").getRules(); + @Override + public Set provideZoneIds() { + 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) { + if (zoneId.equals("FooLocation")) { + return rules; + } + throw new ZoneRulesException("Invalid"); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/AbstractTest.java b/jdk/test/java/time/test/java/time/AbstractTest.java new file mode 100644 index 00000000000..6d4d1340964 --- /dev/null +++ b/jdk/test/java/time/test/java/time/AbstractTest.java @@ -0,0 +1,131 @@ +/* + * 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) 2011-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 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.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * Base test class. + */ +public abstract class AbstractTest { + + protected static boolean isIsoLeap(long year) { + if (year % 4 != 0) { + return false; + } + if (year % 100 == 0 && year % 400 != 0) { + return false; + } + return true; + } + + protected static void assertSerializable(Object o) throws IOException, ClassNotFoundException { + Object deserialisedObject = writeThenRead(o); + assertEquals(deserialisedObject, o); + } + + protected static void assertSerializableAndSame(Object o) throws IOException, ClassNotFoundException { + Object deserialisedObject = writeThenRead(o); + assertSame(deserialisedObject, o); + } + + private static Object writeThenRead(Object o) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { + oos.writeObject(o); + } + + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + return ois.readObject(); + } + } + + protected static void assertImmutable(Class cls) { + assertTrue(Modifier.isPublic(cls.getModifiers())); + assertTrue(Modifier.isFinal(cls.getModifiers())); + Field[] fields = cls.getDeclaredFields(); + for (Field field : fields) { + if (field.getName().contains("$") == false) { + if (Modifier.isStatic(field.getModifiers())) { + assertTrue(Modifier.isFinal(field.getModifiers()), "Field:" + field.getName()); + } else { + assertTrue(Modifier.isPrivate(field.getModifiers()), "Field:" + field.getName()); + assertTrue(Modifier.isFinal(field.getModifiers()), "Field:" + field.getName()); + } + } + } + Constructor[] cons = cls.getDeclaredConstructors(); + for (Constructor con : cons) { + assertTrue(Modifier.isPrivate(con.getModifiers())); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/MockSimplePeriod.java b/jdk/test/java/time/test/java/time/MockSimplePeriod.java new file mode 100644 index 00000000000..1c5d8726bed --- /dev/null +++ b/jdk/test/java/time/test/java/time/MockSimplePeriod.java @@ -0,0 +1,174 @@ +/* + * 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 test.java.time; + +import 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.util.Objects; + +import java.time.temporal.Temporal; +import java.time.temporal.TemporalSubtractor; +import java.time.temporal.TemporalAdder; +import java.time.temporal.TemporalUnit; + +/** + * Mock period of time measured using a single unit, such as {@code 3 Days}. + */ +public final class MockSimplePeriod + implements TemporalAdder, TemporalSubtractor, 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 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; + } + + //----------------------------------------------------------------------- + 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/test/java/time/TestClock_Fixed.java b/jdk/test/java/time/test/java/time/TestClock_Fixed.java new file mode 100644 index 00000000000..cf07ceea07b --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestClock_Fixed.java @@ -0,0 +1,95 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test fixed clock. + */ +@Test +public class TestClock_Fixed { + + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant(); + + //------------------------------------------------------------------------- + public void test_withZone_same() { + Clock test = Clock.fixed(INSTANT, PARIS); + Clock changed = test.withZone(PARIS); + assertSame(test, changed); + } + + //----------------------------------------------------------------------- + public void test_toString() { + Clock test = Clock.fixed(INSTANT, PARIS); + assertEquals(test.toString(), "FixedClock[2008-06-30T09:30:10.000000500Z,Europe/Paris]"); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestClock_Offset.java b/jdk/test/java/time/test/java/time/TestClock_Offset.java new file mode 100644 index 00000000000..ed62300e681 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestClock_Offset.java @@ -0,0 +1,93 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import java.time.Clock; +import java.time.Duration; +import java.time.ZoneId; + +import org.testng.annotations.Test; + +/** + * Test offset clock. + */ +@Test +public class TestClock_Offset { + + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final Duration OFFSET = Duration.ofSeconds(2); + + //------------------------------------------------------------------------- + public void test_withZone_same() { + Clock test = Clock.offset(Clock.system(PARIS), OFFSET); + Clock changed = test.withZone(PARIS); + assertSame(test, changed); + } + + //----------------------------------------------------------------------- + public void test_toString() { + Clock test = Clock.offset(Clock.systemUTC(), OFFSET); + assertEquals(test.toString(), "OffsetClock[SystemClock[Z],PT2S]"); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestClock_System.java b/jdk/test/java/time/test/java/time/TestClock_System.java new file mode 100644 index 00000000000..00e9bbffe84 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestClock_System.java @@ -0,0 +1,89 @@ +/* + * 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; + +import java.time.*; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import org.testng.annotations.Test; + +/** + * Test system clock. + */ +@Test +public class TestClock_System { + + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + + public void test_withZone_same() { + Clock test = Clock.system(PARIS); + Clock changed = test.withZone(PARIS); + assertSame(test, changed); + } + + //----------------------------------------------------------------------- + public void test_toString() { + Clock test = Clock.system(PARIS); + assertEquals(test.toString(), "SystemClock[Europe/Paris]"); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestClock_Tick.java b/jdk/test/java/time/test/java/time/TestClock_Tick.java new file mode 100644 index 00000000000..0e8fdca4e05 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestClock_Tick.java @@ -0,0 +1,97 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import java.time.Clock; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.testng.annotations.Test; + +/** + * Test tick clock. + */ +@Test +public class TestClock_Tick { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)); + + //------------------------------------------------------------------------- + public void test_withZone_same() { + Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)); + Clock changed = test.withZone(PARIS); + assertSame(test, changed); + } + + //----------------------------------------------------------------------- + public void test_toString() { + Clock test = Clock.tick(Clock.systemUTC(), Duration.ofMillis(500)); + assertEquals(test.toString(), "TickClock[SystemClock[Z],PT0.5S]"); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestDuration.java b/jdk/test/java/time/test/java/time/TestDuration.java new file mode 100644 index 00000000000..2b2d8105003 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestDuration.java @@ -0,0 +1,239 @@ +/* + * 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) 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 test.java.time; + +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.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.time.Duration; + +import org.testng.annotations.Test; + +/** + * Test Duration. + */ +@Test +public class TestDuration extends AbstractTest { + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(Duration.class); + } + + //----------------------------------------------------------------------- + @Test(groups={"implementation"}) + public void test_interfaces() { + assertTrue(Serializable.class.isAssignableFrom(Duration.class)); + assertTrue(Comparable.class.isAssignableFrom(Duration.class)); + } + + //----------------------------------------------------------------------- + // serialization + //----------------------------------------------------------------------- + @Test(groups={"implementation"}) + public void test_deserializationSingleton() throws Exception { + Duration orginal = Duration.ZERO; + 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); + Duration ser = (Duration) in.readObject(); + assertSame(ser, Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void plus_zeroReturnsThis() { + Duration t = Duration.ofSeconds(-1); + assertSame(t.plus(Duration.ZERO), t); + } + + @Test(groups={"implementation"}) + public void plus_zeroSingleton() { + Duration t = Duration.ofSeconds(-1); + assertSame(t.plus(Duration.ofSeconds(1)), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void plusSeconds_zeroReturnsThis() { + Duration t = Duration.ofSeconds(-1); + assertSame(t.plusSeconds(0), t); + } + + @Test(groups={"implementation"}) + public void plusSeconds_zeroSingleton() { + Duration t = Duration.ofSeconds(-1); + assertSame(t.plusSeconds(1), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void plusMillis_zeroReturnsThis() { + Duration t = Duration.ofSeconds(-1, 2000000); + assertSame(t.plusMillis(0), t); + } + + @Test(groups={"implementation"}) + public void plusMillis_zeroSingleton() { + Duration t = Duration.ofSeconds(-1, 2000000); + assertSame(t.plusMillis(998), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void plusNanos_zeroReturnsThis() { + Duration t = Duration.ofSeconds(-1, 2000000); + assertSame(t.plusNanos(0), t); + } + + @Test(groups={"implementation"}) + public void plusNanos_zeroSingleton() { + Duration t = Duration.ofSeconds(-1, 2000000); + assertSame(t.plusNanos(998000000), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void minus_zeroReturnsThis() { + Duration t = Duration.ofSeconds(1); + assertSame(t.minus(Duration.ZERO), t); + } + + @Test(groups={"implementation"}) + public void minus_zeroSingleton() { + Duration t = Duration.ofSeconds(1); + assertSame(t.minus(Duration.ofSeconds(1)), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void minusSeconds_zeroReturnsThis() { + Duration t = Duration.ofSeconds(1); + assertSame(t.minusSeconds(0), t); + } + + @Test(groups={"implementation"}) + public void minusSeconds_zeroSingleton() { + Duration t = Duration.ofSeconds(1); + assertSame(t.minusSeconds(1), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void minusMillis_zeroReturnsThis() { + Duration t = Duration.ofSeconds(1, 2000000); + assertSame(t.minusMillis(0), t); + } + + @Test(groups={"implementation"}) + public void minusMillis_zeroSingleton() { + Duration t = Duration.ofSeconds(1, 2000000); + assertSame(t.minusMillis(1002), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void minusNanos_zeroReturnsThis() { + Duration t = Duration.ofSeconds(1, 2000000); + assertSame(t.minusNanos(0), t); + } + + @Test(groups={"implementation"}) + public void minusNanos_zeroSingleton() { + Duration t = Duration.ofSeconds(1, 2000000); + assertSame(t.minusNanos(1002000000), Duration.ZERO); + } + + @Test(groups={"implementation"}) + public void test_abs_same() { + Duration base = Duration.ofSeconds(12); + assertSame(base.abs(), base); + } + + void doTest_comparisons_Duration(Duration... durations) { + for (int i = 0; i < durations.length; i++) { + Duration a = durations[i]; + for (int j = 0; j < durations.length; j++) { + 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/TestInstant.java b/jdk/test/java/time/test/java/time/TestInstant.java new file mode 100644 index 00000000000..cf135a1ae2d --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestInstant.java @@ -0,0 +1,77 @@ +/* + * 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; + +import java.time.Instant; + +import org.testng.annotations.Test; + +/** + * Test Instant. + */ +@Test +public class TestInstant extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(Instant.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestLocalDate.java b/jdk/test/java/time/test/java/time/TestLocalDate.java new file mode 100644 index 00000000000..44033123cdf --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestLocalDate.java @@ -0,0 +1,447 @@ +/* + * 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) 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 test.java.time; + +import static java.time.temporal.ChronoField.YEAR; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.time.LocalDate; +import java.time.Month; +import java.time.temporal.ChronoUnit; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test LocalDate. + */ +@Test +public class TestLocalDate extends AbstractTest { + + private LocalDate TEST_2007_07_15; + + @BeforeMethod(groups={"tck", "implementation"}) + public void setUp() { + TEST_2007_07_15 = LocalDate.of(2007, 7, 15); + } + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(LocalDate.class); + } + + //----------------------------------------------------------------------- + // Since plusDays/minusDays actually depends on MJDays, it cannot be used for testing + private LocalDate next(LocalDate date) { + int newDayOfMonth = date.getDayOfMonth() + 1; + if (newDayOfMonth <= date.getMonth().length(isIsoLeap(date.getYear()))) { + return date.withDayOfMonth(newDayOfMonth); + } + date = date.withDayOfMonth(1); + if (date.getMonth() == Month.DECEMBER) { + date = date.withYear(date.getYear() + 1); + } + return date.with(date.getMonth().plus(1)); + } + + private LocalDate previous(LocalDate date) { + int newDayOfMonth = date.getDayOfMonth() - 1; + if (newDayOfMonth > 0) { + return date.withDayOfMonth(newDayOfMonth); + } + date = date.with(date.getMonth().minus(1)); + if (date.getMonth() == Month.DECEMBER) { + date = date.withYear(date.getYear() - 1); + } + return date.withDayOfMonth(date.getMonth().length(isIsoLeap(date.getYear()))); + } + + @Test(groups={"implementation"}) + public void test_with_DateTimeField_long_noChange_same() { + LocalDate t = TEST_2007_07_15.with(YEAR, 2007); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_withYear_int_noChange_same() { + LocalDate t = TEST_2007_07_15.withYear(2007); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_withMonth_int_noChange_same() { + LocalDate t = TEST_2007_07_15.withMonth(7); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_withDayOfMonth_noChange_same() { + LocalDate t = TEST_2007_07_15.withDayOfMonth(15); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_withDayOfYear_noChange_same() { + LocalDate t = TEST_2007_07_15.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_plus_Period_zero() { + LocalDate t = TEST_2007_07_15.plus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_plus_longPeriodUnit_zero() { + LocalDate t = TEST_2007_07_15.plus(0, ChronoUnit.DAYS); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_plusYears_long_noChange_same() { + LocalDate t = TEST_2007_07_15.plusYears(0); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_plusMonths_long_noChange_same() { + LocalDate t = TEST_2007_07_15.plusMonths(0); + assertSame(t, TEST_2007_07_15); + } + + //----------------------------------------------------------------------- + // plusWeeks() + //----------------------------------------------------------------------- + @DataProvider(name="samplePlusWeeksSymmetry") + Object[][] provider_samplePlusWeeksSymmetry() { + return new Object[][] { + {LocalDate.of(-1, 1, 1)}, + {LocalDate.of(-1, 2, 28)}, + {LocalDate.of(-1, 3, 1)}, + {LocalDate.of(-1, 12, 31)}, + {LocalDate.of(0, 1, 1)}, + {LocalDate.of(0, 2, 28)}, + {LocalDate.of(0, 2, 29)}, + {LocalDate.of(0, 3, 1)}, + {LocalDate.of(0, 12, 31)}, + {LocalDate.of(2007, 1, 1)}, + {LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 12, 31)}, + {LocalDate.of(2008, 1, 1)}, + {LocalDate.of(2008, 2, 28)}, + {LocalDate.of(2008, 2, 29)}, + {LocalDate.of(2008, 3, 1)}, + {LocalDate.of(2008, 12, 31)}, + {LocalDate.of(2099, 1, 1)}, + {LocalDate.of(2099, 2, 28)}, + {LocalDate.of(2099, 3, 1)}, + {LocalDate.of(2099, 12, 31)}, + {LocalDate.of(2100, 1, 1)}, + {LocalDate.of(2100, 2, 28)}, + {LocalDate.of(2100, 3, 1)}, + {LocalDate.of(2100, 12, 31)}, + }; + } + + @Test(dataProvider="samplePlusWeeksSymmetry", groups={"implementation"}) + public void test_plusWeeks_symmetry(LocalDate reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + LocalDate t = reference.plusWeeks(weeks).plusWeeks(-weeks); + assertEquals(t, reference); + + t = reference.plusWeeks(-weeks).plusWeeks(weeks); + assertEquals(t, reference); + } + } + + @Test(groups={"implementation"}) + public void test_plusWeeks_noChange_same() { + LocalDate t = TEST_2007_07_15.plusWeeks(0); + assertSame(t, TEST_2007_07_15); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + @DataProvider(name="samplePlusDaysSymmetry") + Object[][] provider_samplePlusDaysSymmetry() { + return new Object[][] { + {LocalDate.of(-1, 1, 1)}, + {LocalDate.of(-1, 2, 28)}, + {LocalDate.of(-1, 3, 1)}, + {LocalDate.of(-1, 12, 31)}, + {LocalDate.of(0, 1, 1)}, + {LocalDate.of(0, 2, 28)}, + {LocalDate.of(0, 2, 29)}, + {LocalDate.of(0, 3, 1)}, + {LocalDate.of(0, 12, 31)}, + {LocalDate.of(2007, 1, 1)}, + {LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 12, 31)}, + {LocalDate.of(2008, 1, 1)}, + {LocalDate.of(2008, 2, 28)}, + {LocalDate.of(2008, 2, 29)}, + {LocalDate.of(2008, 3, 1)}, + {LocalDate.of(2008, 12, 31)}, + {LocalDate.of(2099, 1, 1)}, + {LocalDate.of(2099, 2, 28)}, + {LocalDate.of(2099, 3, 1)}, + {LocalDate.of(2099, 12, 31)}, + {LocalDate.of(2100, 1, 1)}, + {LocalDate.of(2100, 2, 28)}, + {LocalDate.of(2100, 3, 1)}, + {LocalDate.of(2100, 12, 31)}, + }; + } + + @Test(dataProvider="samplePlusDaysSymmetry", groups={"implementation"}) + public void test_plusDays_symmetry(LocalDate reference) { + for (int days = 0; days < 365 * 8; days++) { + LocalDate t = reference.plusDays(days).plusDays(-days); + assertEquals(t, reference); + + t = reference.plusDays(-days).plusDays(days); + assertEquals(t, reference); + } + } + + @Test(groups={"implementation"}) + public void test_plusDays_noChange_same() { + LocalDate t = TEST_2007_07_15.plusDays(0); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_minus_Period_zero() { + LocalDate t = TEST_2007_07_15.minus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_minus_longPeriodUnit_zero() { + LocalDate t = TEST_2007_07_15.minus(0, ChronoUnit.DAYS); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_minusYears_long_noChange_same() { + LocalDate t = TEST_2007_07_15.minusYears(0); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_minusMonths_long_noChange_same() { + LocalDate t = TEST_2007_07_15.minusMonths(0); + assertSame(t, TEST_2007_07_15); + } + + //----------------------------------------------------------------------- + // minusWeeks() + //----------------------------------------------------------------------- + @DataProvider(name="sampleMinusWeeksSymmetry") + Object[][] provider_sampleMinusWeeksSymmetry() { + return new Object[][] { + {LocalDate.of(-1, 1, 1)}, + {LocalDate.of(-1, 2, 28)}, + {LocalDate.of(-1, 3, 1)}, + {LocalDate.of(-1, 12, 31)}, + {LocalDate.of(0, 1, 1)}, + {LocalDate.of(0, 2, 28)}, + {LocalDate.of(0, 2, 29)}, + {LocalDate.of(0, 3, 1)}, + {LocalDate.of(0, 12, 31)}, + {LocalDate.of(2007, 1, 1)}, + {LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 12, 31)}, + {LocalDate.of(2008, 1, 1)}, + {LocalDate.of(2008, 2, 28)}, + {LocalDate.of(2008, 2, 29)}, + {LocalDate.of(2008, 3, 1)}, + {LocalDate.of(2008, 12, 31)}, + {LocalDate.of(2099, 1, 1)}, + {LocalDate.of(2099, 2, 28)}, + {LocalDate.of(2099, 3, 1)}, + {LocalDate.of(2099, 12, 31)}, + {LocalDate.of(2100, 1, 1)}, + {LocalDate.of(2100, 2, 28)}, + {LocalDate.of(2100, 3, 1)}, + {LocalDate.of(2100, 12, 31)}, + }; + } + + @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"implementation"}) + public void test_minusWeeks_symmetry(LocalDate reference) { + for (int weeks = 0; weeks < 365 * 8; weeks++) { + LocalDate t = reference.minusWeeks(weeks).minusWeeks(-weeks); + assertEquals(t, reference); + + t = reference.minusWeeks(-weeks).minusWeeks(weeks); + assertEquals(t, reference); + } + } + + @Test(groups={"implementation"}) + public void test_minusWeeks_noChange_same() { + LocalDate t = TEST_2007_07_15.minusWeeks(0); + assertSame(t, TEST_2007_07_15); + } + + //----------------------------------------------------------------------- + // minusDays() + //----------------------------------------------------------------------- + @DataProvider(name="sampleMinusDaysSymmetry") + Object[][] provider_sampleMinusDaysSymmetry() { + return new Object[][] { + {LocalDate.of(-1, 1, 1)}, + {LocalDate.of(-1, 2, 28)}, + {LocalDate.of(-1, 3, 1)}, + {LocalDate.of(-1, 12, 31)}, + {LocalDate.of(0, 1, 1)}, + {LocalDate.of(0, 2, 28)}, + {LocalDate.of(0, 2, 29)}, + {LocalDate.of(0, 3, 1)}, + {LocalDate.of(0, 12, 31)}, + {LocalDate.of(2007, 1, 1)}, + {LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 12, 31)}, + {LocalDate.of(2008, 1, 1)}, + {LocalDate.of(2008, 2, 28)}, + {LocalDate.of(2008, 2, 29)}, + {LocalDate.of(2008, 3, 1)}, + {LocalDate.of(2008, 12, 31)}, + {LocalDate.of(2099, 1, 1)}, + {LocalDate.of(2099, 2, 28)}, + {LocalDate.of(2099, 3, 1)}, + {LocalDate.of(2099, 12, 31)}, + {LocalDate.of(2100, 1, 1)}, + {LocalDate.of(2100, 2, 28)}, + {LocalDate.of(2100, 3, 1)}, + {LocalDate.of(2100, 12, 31)}, + }; + } + + @Test(dataProvider="sampleMinusDaysSymmetry", groups={"implementation"}) + public void test_minusDays_symmetry(LocalDate reference) { + for (int days = 0; days < 365 * 8; days++) { + LocalDate t = reference.minusDays(days).minusDays(-days); + assertEquals(t, reference); + + t = reference.minusDays(-days).minusDays(days); + assertEquals(t, reference); + } + } + + @Test(groups={"implementation"}) + public void test_minusDays_noChange_same() { + LocalDate t = TEST_2007_07_15.minusDays(0); + assertSame(t, TEST_2007_07_15); + } + + @Test(groups={"implementation"}) + public void test_toEpochDay_fromMJDays_symmetry() { + long date_0000_01_01 = -678941 - 40587; + + LocalDate test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i < 700000; i++) { + assertEquals(LocalDate.ofEpochDay(test.toEpochDay()), test); + test = next(test); + } + test = LocalDate.of(0, 1, 1); + for (long i = date_0000_01_01; i > -2000000; i--) { + assertEquals(LocalDate.ofEpochDay(test.toEpochDay()), test); + test = previous(test); + } + } + + void doTest_comparisons_LocalDate(LocalDate... localDates) { + for (int i = 0; i < localDates.length; i++) { + LocalDate a = localDates[i]; + for (int j = 0; j < localDates.length; j++) { + LocalDate b = localDates[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(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 new file mode 100644 index 00000000000..d850be50715 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestLocalDateTime.java @@ -0,0 +1,570 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Period; +import java.time.temporal.ChronoUnit; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test LocalDateTime. + */ +@Test +public class TestLocalDateTime extends AbstractTest { + + private LocalDateTime TEST_2007_07_15_12_30_40_987654321 = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321); + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(LocalDateTime.class); + } + + //----------------------------------------------------------------------- + @DataProvider(name="sampleDates") + Object[][] provider_sampleDates() { + return new Object[][] { + {2008, 7, 5}, + {2007, 7, 5}, + {2006, 7, 5}, + {2005, 7, 5}, + {2004, 1, 1}, + {-1, 1, 2}, + }; + } + + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {0, 0, 0, 0}, + {0, 0, 0, 1}, + {0, 0, 1, 0}, + {0, 0, 1, 1}, + {0, 1, 0, 0}, + {0, 1, 0, 1}, + {0, 1, 1, 0}, + {0, 1, 1, 1}, + {1, 0, 0, 0}, + {1, 0, 0, 1}, + {1, 0, 1, 0}, + {1, 0, 1, 1}, + {1, 1, 0, 0}, + {1, 1, 0, 1}, + {1, 1, 1, 0}, + {1, 1, 1, 1}, + }; + } + + @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()); + } + + @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()); + } + + @Test(groups={"implementation"}) + public void test_withDayOfMonth_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfMonth(15); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_withDayOfYear_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_withHour_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withHour(12); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_withMinute_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMinute(30); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_withSecond_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withSecond(40); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_withNanoOfSecond_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withNano(987654321); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_plus_adjuster_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(Period.ZERO); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plus_Period_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plus_longPeriodUnit_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(0, ChronoUnit.DAYS); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plusYears_int_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(0); + assertSame(TEST_2007_07_15_12_30_40_987654321, t); + } + + @Test(groups={"implementation"}) + public void test_plusMonths_int_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plusWeeks_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plusDays_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_plusHours_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusHours(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_plusMinutes_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_plusSeconds_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_plusNanos_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_minus_adjuster_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(Period.ZERO); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minus_Period_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minus_longPeriodUnit_zero() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(0, ChronoUnit.DAYS); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minusYears_int_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minusMonths_int_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minusWeeks_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minusDays_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @Test(groups={"implementation"}) + public void test_minusHours_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusHours(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_minusMinutes_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_minusSeconds_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusSeconds(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + @Test(groups={"implementation"}) + public void test_minusNanos_noChange() { + LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusNanos(0); + assertSame(t, TEST_2007_07_15_12_30_40_987654321); + } + + @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()); + } + + @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); + } + + @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); + } + + //----------------------------------------------------------------------- + // getDate() + //----------------------------------------------------------------------- + @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); + } + + //----------------------------------------------------------------------- + // getTime() + //----------------------------------------------------------------------- + @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); + } + + void test_comparisons_LocalDateTime(LocalDate... localDates) { + test_comparisons_LocalDateTime( + localDates, + LocalTime.MIDNIGHT, + LocalTime.of(0, 0, 0, 999999999), + LocalTime.of(0, 0, 59, 0), + LocalTime.of(0, 0, 59, 999999999), + LocalTime.of(0, 59, 0, 0), + LocalTime.of(0, 59, 59, 999999999), + LocalTime.NOON, + LocalTime.of(12, 0, 0, 999999999), + LocalTime.of(12, 0, 59, 0), + LocalTime.of(12, 0, 59, 999999999), + LocalTime.of(12, 59, 0, 0), + LocalTime.of(12, 59, 59, 999999999), + LocalTime.of(23, 0, 0, 0), + LocalTime.of(23, 0, 0, 999999999), + LocalTime.of(23, 0, 59, 0), + LocalTime.of(23, 0, 59, 999999999), + LocalTime.of(23, 59, 0, 0), + LocalTime.of(23, 59, 59, 999999999) + ); + } + + void test_comparisons_LocalDateTime(LocalDate[] localDates, LocalTime... localTimes) { + LocalDateTime[] localDateTimes = new LocalDateTime[localDates.length * localTimes.length]; + int i = 0; + + for (LocalDate localDate : localDates) { + for (LocalTime localTime : localTimes) { + localDateTimes[i++] = LocalDateTime.of(localDate, localTime); + } + } + + doTest_comparisons_LocalDateTime(localDateTimes); + } + + void doTest_comparisons_LocalDateTime(LocalDateTime[] localDateTimes) { + for (int i = 0; i < localDateTimes.length; i++) { + LocalDateTime a = localDateTimes[i]; + for (int j = 0; j < localDateTimes.length; j++) { + LocalDateTime b = localDateTimes[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + +} diff --git a/jdk/test/java/time/test/java/time/TestLocalTime.java b/jdk/test/java/time/test/java/time/TestLocalTime.java new file mode 100644 index 00000000000..0a0b27796b1 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestLocalTime.java @@ -0,0 +1,188 @@ +/* + * 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) 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 test.java.time; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +import java.time.LocalTime; + +import org.testng.annotations.Test; + +/** + * Test LocalTime. + */ +@Test +public class TestLocalTime extends AbstractTest { + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(LocalTime.class); + } + + //----------------------------------------------------------------------- + private void check(LocalTime time, int h, int m, int s, int n) { + assertEquals(time.getHour(), h); + assertEquals(time.getMinute(), m); + assertEquals(time.getSecond(), s); + assertEquals(time.getNano(), n); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck","implementation"}) + public void constant_MIDNIGHT() { + check(LocalTime.MIDNIGHT, 0, 0, 0, 0); + } + + @Test(groups={"implementation"}) + public void constant_MIDNIGHT_same() { + assertSame(LocalTime.MIDNIGHT, LocalTime.MIDNIGHT); + assertSame(LocalTime.MIDNIGHT, LocalTime.of(0, 0)); + } + + @Test(groups={"tck","implementation"}) + public void constant_MIDDAY() { + check(LocalTime.NOON, 12, 0, 0, 0); + } + + @Test(groups={"implementation"}) + public void constant_MIDDAY_same() { + assertSame(LocalTime.NOON, LocalTime.NOON); + assertSame(LocalTime.NOON, LocalTime.of(12, 0)); + } + + //----------------------------------------------------------------------- + @Test(groups={"tck","implementation"}) + public void constant_MIN_TIME() { + check(LocalTime.MIN, 0, 0, 0, 0); + } + + @Test(groups={"implementation"}) + public void constant_MIN_TIME_same() { + assertSame(LocalTime.MIN, LocalTime.of(0, 0)); + } + + @Test(groups={"tck","implementation"}) + public void constant_MAX_TIME() { + check(LocalTime.MAX, 23, 59, 59, 999999999); + } + + @Test(groups={"implementation"}) + public void constant_MAX_TIME_same() { + assertSame(LocalTime.NOON, LocalTime.NOON); + assertSame(LocalTime.NOON, LocalTime.of(12, 0)); + } + + @Test(groups={"implementation"}) + public void factory_time_2ints_singletons() { + for (int i = 0; i < 24; i++) { + LocalTime test1 = LocalTime.of(i, 0); + LocalTime test2 = LocalTime.of(i, 0); + assertSame(test1, test2); + } + } + + @Test(groups={"implementation"}) + public void factory_time_3ints_singletons() { + for (int i = 0; i < 24; i++) { + LocalTime test1 = LocalTime.of(i, 0, 0); + LocalTime test2 = LocalTime.of(i, 0, 0); + assertSame(test1, test2); + } + } + + @Test(groups={"implementation"}) + public void factory_time_4ints_singletons() { + for (int i = 0; i < 24; i++) { + LocalTime test1 = LocalTime.of(i, 0, 0, 0); + LocalTime test2 = LocalTime.of(i, 0, 0, 0); + assertSame(test1, test2); + } + } + + @Test(groups={"implementation"}) + public void factory_ofSecondOfDay_singletons() { + for (int i = 0; i < 24; i++) { + LocalTime test1 = LocalTime.ofSecondOfDay(i * 60L * 60L); + LocalTime test2 = LocalTime.of(i, 0); + assertSame(test1, test2); + } + } + + @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++) { + LocalTime test1 = LocalTime.ofNanoOfDay(i * 1000000000L * 60L * 60L); + LocalTime test2 = LocalTime.of(i, 0); + assertSame(test1, test2); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/TestPeriod.java b/jdk/test/java/time/test/java/time/TestPeriod.java new file mode 100644 index 00000000000..f7caf9e334b --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestPeriod.java @@ -0,0 +1,1575 @@ +/* + * 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; + +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; + +/** + * 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); + } + + //----------------------------------------------------------------------- + // factories + //----------------------------------------------------------------------- + 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); + } + + //----------------------------------------------------------------------- + // 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); + } + + //----------------------------------------------------------------------- + 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); + 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 new file mode 100644 index 00000000000..1d3a8abe373 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestPeriodParser.java @@ -0,0 +1,281 @@ +/* + * 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/TestZoneId.java b/jdk/test/java/time/test/java/time/TestZoneId.java new file mode 100644 index 00000000000..5e9380391df --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestZoneId.java @@ -0,0 +1,1084 @@ +/* + * 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; + +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.format.TextStyle; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneRules; +import java.time.zone.ZoneRulesException; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ZoneId. + */ +@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; + + //----------------------------------------------------------------------- + // Basics + //----------------------------------------------------------------------- + public void test_immutable() { + Class cls = ZoneId.class; + assertTrue(Modifier.isPublic(cls.getModifiers())); + Field[] fields = cls.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) == false) { + assertTrue(Modifier.isPrivate(field.getModifiers())); + assertTrue(Modifier.isFinal(field.getModifiers()) || + (Modifier.isVolatile(field.getModifiers()) && Modifier.isTransient(field.getModifiers()))); + } + } + } + + 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.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()); + } + + @Test(expectedExceptions = DateTimeException.class) + public void test_systemDefault_unableToConvert_badFormat() { + TimeZone current = TimeZone.getDefault(); + try { + TimeZone.setDefault(new SimpleTimeZone(127, "Something Weird")); + ZoneId.systemDefault(); + } finally { + TimeZone.setDefault(current); + } + } + + @Test(expectedExceptions = ZoneRulesException.class) + public void test_systemDefault_unableToConvert_unknownId() { + TimeZone current = TimeZone.getDefault(); + try { + TimeZone.setDefault(new SimpleTimeZone(127, "SomethingWeird")); + ZoneId.systemDefault(); + } finally { + TimeZone.setDefault(current); + } + } + + //----------------------------------------------------------------------- + // 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"}, + {"+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="String_Fixed") + 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.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); + } + + @Test(dataProvider="String_Fixed") + 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.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); + } + + @Test(dataProvider="String_Fixed") + 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.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 + //----------------------------------------------------------------------- + public void test_London() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getId(), "Europe/London"); + assertEquals(test.getRules().isFixedOffset(), false); + } + + public void test_London_getOffset() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + } + + public void test_London_getOffset_toDST() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + // cutover at 01:00Z + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + } + + public void test_London_getOffset_fromDST() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + // cutover at 01:00Z + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(0)); + } + + public void test_London_getOffsetInfo() { + ZoneId test = ZoneId.of("Europe/London"); + checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(0), 1); + } + + public void test_London_getOffsetInfo_toDST() { + ZoneId test = ZoneId.of("Europe/London"); + checkOffset(test.getRules(), createLDT(2008, 3, 24), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 25), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 26), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 27), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 29), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 30), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 31), ZoneOffset.ofHours(1), 1); + // cutover at 01:00Z + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 1, 30, 0, 0), ZoneOffset.ofHours(0), GAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), ZoneOffset.ofHours(1), 1); + } + + public void test_London_getOffsetInfo_fromDST() { + ZoneId test = ZoneId.of("Europe/London"); + checkOffset(test.getRules(), createLDT(2008, 10, 24), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 25), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 26), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 27), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 29), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 30), ZoneOffset.ofHours(0), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 31), ZoneOffset.ofHours(0), 1); + // cutover at 01:00Z + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 1, 30, 0, 0), ZoneOffset.ofHours(1), OVERLAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), ZoneOffset.ofHours(0), 1); + } + + public void test_London_getOffsetInfo_gap() { + ZoneId test = ZoneId.of("Europe/London"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(0), GAP); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(0)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(1)); + assertEquals(trans.getInstant(), dateTime.toInstant(ZoneOffset.UTC)); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0)); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(0))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_London_getOffsetInfo_overlap() { + ZoneId test = ZoneId.of("Europe/London"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(1), OVERLAP); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(1)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(0)); + assertEquals(trans.getInstant(), dateTime.toInstant(ZoneOffset.UTC)); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0)); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(1))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + //----------------------------------------------------------------------- + // Europe/Paris + //----------------------------------------------------------------------- + public void test_Paris() { + ZoneId test = ZoneId.of("Europe/Paris"); + assertEquals(test.getId(), "Europe/Paris"); + assertEquals(test.getRules().isFixedOffset(), false); + } + + public void test_Paris_getOffset() { + ZoneId test = ZoneId.of("Europe/Paris"); + assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + } + + public void test_Paris_getOffset_toDST() { + ZoneId test = ZoneId.of("Europe/Paris"); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + // cutover at 01:00Z + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + } + + public void test_Paris_getOffset_fromDST() { + ZoneId test = ZoneId.of("Europe/Paris"); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + // cutover at 01:00Z + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(2)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(1)); + } + + public void test_Paris_getOffsetInfo() { + ZoneId test = ZoneId.of("Europe/Paris"); + checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(1), 1); + } + + public void test_Paris_getOffsetInfo_toDST() { + ZoneId test = ZoneId.of("Europe/Paris"); + checkOffset(test.getRules(), createLDT(2008, 3, 24), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 25), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 26), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 27), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 29), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 30), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 31), ZoneOffset.ofHours(2), 1); + // cutover at 01:00Z which is 02:00+01:00(local Paris time) + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 2, 30, 0, 0), ZoneOffset.ofHours(1), GAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), ZoneOffset.ofHours(2), 1); + } + + public void test_Paris_getOffsetInfo_fromDST() { + ZoneId test = ZoneId.of("Europe/Paris"); + checkOffset(test.getRules(), createLDT(2008, 10, 24), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 25), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 26), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 27), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 29), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 30), ZoneOffset.ofHours(1), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 31), ZoneOffset.ofHours(1), 1); + // cutover at 01:00Z which is 02:00+01:00(local Paris time) + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), ZoneOffset.ofHours(2), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 2, 30, 0, 0), ZoneOffset.ofHours(2), OVERLAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), ZoneOffset.ofHours(1), 1); + } + + public void test_Paris_getOffsetInfo_gap() { + ZoneId test = ZoneId.of("Europe/Paris"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(1), GAP); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(1)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(2)); + assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(1))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherDis = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherDis)); + assertEquals(trans.hashCode(), otherDis.hashCode()); + } + + public void test_Paris_getOffsetInfo_overlap() { + ZoneId test = ZoneId.of("Europe/Paris"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(2), OVERLAP); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(2)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(1)); + assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(2))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherDis = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherDis)); + assertEquals(trans.hashCode(), otherDis.hashCode()); + } + + //----------------------------------------------------------------------- + // America/New_York + //----------------------------------------------------------------------- + public void test_NewYork() { + ZoneId test = ZoneId.of("America/New_York"); + assertEquals(test.getId(), "America/New_York"); + assertEquals(test.getRules().isFixedOffset(), false); + } + + public void test_NewYork_getOffset() { + ZoneId test = ZoneId.of("America/New_York"); + ZoneOffset offset = ZoneOffset.ofHours(-5); + assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5)); + } + + public void test_NewYork_getOffset_toDST() { + ZoneId test = ZoneId.of("America/New_York"); + ZoneOffset offset = ZoneOffset.ofHours(-5); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4)); + // cutover at 02:00 local + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4)); + } + + public void test_NewYork_getOffset_fromDST() { + ZoneId test = ZoneId.of("America/New_York"); + ZoneOffset offset = ZoneOffset.ofHours(-4); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5)); + // cutover at 02:00 local + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4)); + assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5)); + } + + public void test_NewYork_getOffsetInfo() { + ZoneId test = ZoneId.of("America/New_York"); + checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1); + } + + public void test_NewYork_getOffsetInfo_toDST() { + ZoneId test = ZoneId.of("America/New_York"); + checkOffset(test.getRules(), createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1); + // cutover at 02:00 local + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 2, 30, 0, 0), ZoneOffset.ofHours(-5), GAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1); + } + + public void test_NewYork_getOffsetInfo_fromDST() { + ZoneId test = ZoneId.of("America/New_York"); + checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1); + checkOffset(test.getRules(), createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1); + // cutover at 02:00 local + checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1); + checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 1, 30, 0, 0), ZoneOffset.ofHours(-4), OVERLAP); + checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1); + } + + public void test_NewYork_getOffsetInfo_gap() { + ZoneId test = ZoneId.of("America/New_York"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(-5), GAP); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4)); + assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, 0, 0, ZoneOffset.ofHours(-5))); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-6)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-3)), false); + assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(-5))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + public void test_NewYork_getOffsetInfo_overlap() { + ZoneId test = ZoneId.of("America/New_York"); + final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0); + ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(-4), OVERLAP); + assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4)); + assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5)); + assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, 0, 0, ZoneOffset.ofHours(-4))); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false); + assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]"); + + assertFalse(trans.equals(null)); + assertFalse(trans.equals(ZoneOffset.ofHours(-4))); + assertTrue(trans.equals(trans)); + + final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime); + assertTrue(trans.equals(otherTrans)); + + assertEquals(trans.hashCode(), otherTrans.hashCode()); + } + + //----------------------------------------------------------------------- + // getXxx() isXxx() + //----------------------------------------------------------------------- + public void test_get_Tzdb() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getId(), "Europe/London"); + assertEquals(test.getRules().isFixedOffset(), false); + } + + public void test_get_TzdbFixed() { + ZoneId test = ZoneId.of("+01:30"); + assertEquals(test.getId(), "+01:30"); + 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); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + private Instant createInstant(int year, int month, int day, ZoneOffset offset) { + return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset); + } + + private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) { + return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset); + } + + private ZonedDateTime createZDT(int year, int month, int day, int hour, int min, int sec, int nano, ZoneId zone) { + return LocalDateTime.of(year, month, day, hour, min, sec, nano).atZone(zone); + } + + private LocalDateTime createLDT(int year, int month, int day) { + return LocalDateTime.of(year, month, day, 0, 0); + } + + private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) { + List validOffsets = rules.getValidOffsets(dateTime); + assertEquals(validOffsets.size(), type); + assertEquals(rules.getOffset(dateTime), offset); + if (type == 1) { + assertEquals(validOffsets.get(0), offset); + return null; + } else { + ZoneOffsetTransition zot = rules.getTransition(dateTime); + assertNotNull(zot); + assertEquals(zot.isOverlap(), type == 2); + assertEquals(zot.isGap(), type == 0); + assertEquals(zot.isValidOffset(offset), type == 2); + return zot; + } + } + +} diff --git a/jdk/test/java/time/test/java/time/TestZoneOffset.java b/jdk/test/java/time/test/java/time/TestZoneOffset.java new file mode 100644 index 00000000000..b6df12f1abf --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestZoneOffset.java @@ -0,0 +1,84 @@ +/* + * 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; + +import static org.testng.Assert.assertSame; + +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test ZoneOffset. + */ +@Test +public class TestZoneOffset extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(ZoneOffset.class); + } + + @Test + public void test_factory_ofTotalSecondsSame() { + assertSame(ZoneOffset.ofTotalSeconds(0), ZoneOffset.UTC); + } + +} diff --git a/jdk/test/java/time/test/java/time/TestZonedDateTime.java b/jdk/test/java/time/test/java/time/TestZonedDateTime.java new file mode 100644 index 00000000000..ee9bbaef8a3 --- /dev/null +++ b/jdk/test/java/time/test/java/time/TestZonedDateTime.java @@ -0,0 +1,77 @@ +/* + * 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; + +import java.time.ZonedDateTime; + +import org.testng.annotations.Test; + +/** + * Test ZonedDateTime. + */ +@Test +public class TestZonedDateTime extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(ZonedDateTime.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/AbstractTestPrinterParser.java b/jdk/test/java/time/test/java/time/format/AbstractTestPrinterParser.java new file mode 100644 index 00000000000..c1b0ad2a18e --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/AbstractTestPrinterParser.java @@ -0,0 +1,147 @@ +/* + * 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) 2011-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 java.util.Locale; + +import java.time.DateTimeException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Abstract PrinterParser test. + */ +@Test +public class AbstractTestPrinterParser { + + protected StringBuilder buf; + protected DateTimeFormatterBuilder builder; + protected TemporalAccessor dta; + protected Locale locale; + protected DateTimeFormatSymbols symbols; + + + @BeforeMethod(groups={"tck"}) + public void setUp() { + buf = new StringBuilder(); + builder = new DateTimeFormatterBuilder(); + dta = ZonedDateTime.of(LocalDateTime.of(2011, 6, 30, 12, 30, 40, 0), ZoneId.of("Europe/Paris")); + locale = Locale.ENGLISH; + symbols = DateTimeFormatSymbols.STANDARD; + } + + protected void setCaseSensitive(boolean caseSensitive) { + if (caseSensitive) { + builder.parseCaseSensitive(); + } else { + builder.parseCaseInsensitive(); + } + } + + protected void setStrict(boolean strict) { + if (strict) { + builder.parseStrict(); + } else { + builder.parseLenient(); + } + } + + protected DateTimeFormatter getFormatter() { + return builder.toFormatter(locale).withSymbols(symbols); + } + + protected DateTimeFormatter getFormatter(char c) { + return builder.appendLiteral(c).toFormatter(locale).withSymbols(symbols); + } + + protected DateTimeFormatter getFormatter(String s) { + return builder.appendLiteral(s).toFormatter(locale).withSymbols(symbols); + } + + protected DateTimeFormatter getFormatter(TemporalField field, TextStyle style) { + return builder.appendText(field, style).toFormatter(locale).withSymbols(symbols); + } + + protected DateTimeFormatter getFormatter(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) { + return builder.appendValue(field, minWidth, maxWidth, signStyle).toFormatter(locale).withSymbols(symbols); + } + + protected DateTimeFormatter getFormatter(String pattern, String noOffsetText) { + return builder.appendOffset(pattern, noOffsetText).toFormatter(locale).withSymbols(symbols); + } + + protected static final TemporalAccessor EMPTY_DTA = new TemporalAccessor() { + public boolean isSupported(TemporalField field) { + return true; + } + @Override + public long getLong(TemporalField field) { + throw new DateTimeException("Mock"); + } + }; +} diff --git a/jdk/test/java/time/test/java/time/format/MockIOExceptionAppendable.java b/jdk/test/java/time/test/java/time/format/MockIOExceptionAppendable.java new file mode 100644 index 00000000000..8cdedccdf8f --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/MockIOExceptionAppendable.java @@ -0,0 +1,84 @@ +/* + * 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 java.io.IOException; + +/** + * Mock Appendable that throws IOException. + */ +public class MockIOExceptionAppendable implements Appendable { + + public Appendable append(CharSequence csq) throws IOException { + throw new IOException(); + } + + public Appendable append(char c) throws IOException { + throw new IOException(); + } + + public Appendable append(CharSequence csq, int start, int end) + throws IOException { + throw new IOException(); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java b/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java new file mode 100644 index 00000000000..c2fe6290a5d --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java @@ -0,0 +1,133 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.time.format.DateTimeBuilder; +import java.text.ParsePosition; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test CharLiteralPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestCharLiteralParser extends AbstractTestPrinterParser { + + @DataProvider(name="success") + Object[][] data_success() { + return new Object[][] { + // match + {'a', true, "a", 0, 1}, + {'a', true, "aOTHER", 0, 1}, + {'a', true, "OTHERaOTHER", 5, 6}, + {'a', true, "OTHERa", 5, 6}, + + // no match + {'a', true, "", 0, 0}, + {'a', true, "a", 1, 1}, + {'a', true, "A", 0, 0}, + {'a', true, "b", 0, 0}, + {'a', true, "OTHERbOTHER", 5, 5}, + {'a', true, "OTHERb", 5, 5}, + + // case insensitive + {'a', false, "a", 0, 1}, + {'a', false, "A", 0, 1}, + }; + } + + @Test(dataProvider="success") + public void test_parse_success(char c, boolean caseSensitive, + String text, int pos, int expectedPos) { + setCaseSensitive(caseSensitive); + ParsePosition ppos = new ParsePosition(pos); + DateTimeBuilder result = + getFormatter(c).parseToBuilder(text, ppos); + if (ppos.getErrorIndex() != -1) { + assertEquals(ppos.getIndex(), expectedPos); + } else { + assertEquals(ppos.getIndex(), expectedPos); + assertEquals(result.getCalendricalList().size(), 0); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {'a', "a", -1, IndexOutOfBoundsException.class}, + {'a', "a", 2, IndexOutOfBoundsException.class}, + }; + } + + @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); + } 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 new file mode 100644 index 00000000000..f2c1f7d65b1 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java @@ -0,0 +1,102 @@ +/* + * 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 org.testng.annotations.Test; + +/** + * Test CharLiteralPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestCharLiteralPrinter extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + public void test_print_emptyCalendrical() throws Exception { + buf.append("EXISTING"); + getFormatter('a').printTo(EMPTY_DTA, buf); + assertEquals(buf.toString(), "EXISTINGa"); + } + + public void test_print_dateTime() throws Exception { + buf.append("EXISTING"); + getFormatter('a').printTo(dta, buf); + assertEquals(buf.toString(), "EXISTINGa"); + } + + public void test_print_emptyAppendable() throws Exception { + getFormatter('a').printTo(dta, buf); + assertEquals(buf.toString(), "a"); + } + + //----------------------------------------------------------------------- + public void test_toString() throws Exception { + assertEquals(getFormatter('a').toString(), "'a'"); + } + + //----------------------------------------------------------------------- + public void test_toString_apos() throws Exception { + assertEquals(getFormatter('\'').toString(), "''"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java new file mode 100644 index 00000000000..fe2d408a6f9 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java @@ -0,0 +1,91 @@ +/* + * 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) 2011-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.assertSame; + +import java.util.Locale; + +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatSymbols. + */ +@Test +public class TestDateTimeFormatSymbols { + + @Test(groups={"implementation"}) + public void test_of_Locale_cached() { + DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.of(Locale.CANADA); + DateTimeFormatSymbols loc2 = DateTimeFormatSymbols.of(Locale.CANADA); + assertSame(loc1, loc2); + } + + //----------------------------------------------------------------------- + @Test(groups={"implementation"}) + public void test_ofDefaultLocale_cached() { + DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.ofDefaultLocale(); + DateTimeFormatSymbols loc2 = DateTimeFormatSymbols.ofDefaultLocale(); + assertSame(loc1, loc2); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java new file mode 100644 index 00000000000..61b0806f958 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java @@ -0,0 +1,95 @@ +/* + * 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 java.time.temporal.ChronoField.DAY_OF_MONTH; +import static org.testng.Assert.assertSame; + +import java.util.Locale; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatter. + */ +@Test +public class TestDateTimeFormatter { + // TODO these tests are not tck, as they refer to a non-public class + // rewrite whole test case to use BASIC_FORMATTER or similar + + @BeforeMethod(groups={"tck"}) + public void setUp() { + } + + @Test(groups={"implementation"}) + public void test_withLocale_same() throws Exception { + DateTimeFormatter base = + new DateTimeFormatterBuilder().appendLiteral("ONE") + .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) + .toFormatter(Locale.ENGLISH) + .withSymbols(DateTimeFormatSymbols.STANDARD); + DateTimeFormatter test = base.withLocale(Locale.ENGLISH); + assertSame(test, base); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java new file mode 100644 index 00000000000..5e7ab3ef7cb --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java @@ -0,0 +1,93 @@ +/* + * 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.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.Collections; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatters. + */ +@Test +public class TestDateTimeFormatters { + + @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()); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java b/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java new file mode 100644 index 00000000000..3a737f33ed2 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java @@ -0,0 +1,95 @@ +/* + * 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 new file mode 100644 index 00000000000..ab8cec39822 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java @@ -0,0 +1,186 @@ +/* + * 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) 2011-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 java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.testng.Assert.assertEquals; + +import java.util.Locale; + +import java.time.ZonedDateTime; +import java.time.temporal.TemporalField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test SimpleDateTimeTextProvider. + */ +@Test(groups={"implementation"}) +public class TestDateTimeTextProvider extends AbstractTestPrinterParser { + + Locale enUS = new Locale("en", "US"); + Locale ptBR = new Locale("pt", "BR"); + + //----------------------------------------------------------------------- + @DataProvider(name = "Text") + Object[][] data_text() { + return new Object[][] { + {DAY_OF_WEEK, 1, TextStyle.SHORT, enUS, "Mon"}, + {DAY_OF_WEEK, 2, TextStyle.SHORT, enUS, "Tue"}, + {DAY_OF_WEEK, 3, TextStyle.SHORT, enUS, "Wed"}, + {DAY_OF_WEEK, 4, TextStyle.SHORT, enUS, "Thu"}, + {DAY_OF_WEEK, 5, TextStyle.SHORT, enUS, "Fri"}, + {DAY_OF_WEEK, 6, TextStyle.SHORT, enUS, "Sat"}, + {DAY_OF_WEEK, 7, TextStyle.SHORT, enUS, "Sun"}, + + {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "Seg"}, + {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "Ter"}, + {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "Qua"}, + {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "Qui"}, + {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "Sex"}, + {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "S\u00E1b"}, + {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "Dom"}, + + {DAY_OF_WEEK, 1, TextStyle.FULL, enUS, "Monday"}, + {DAY_OF_WEEK, 2, TextStyle.FULL, enUS, "Tuesday"}, + {DAY_OF_WEEK, 3, TextStyle.FULL, enUS, "Wednesday"}, + {DAY_OF_WEEK, 4, TextStyle.FULL, enUS, "Thursday"}, + {DAY_OF_WEEK, 5, TextStyle.FULL, enUS, "Friday"}, + {DAY_OF_WEEK, 6, TextStyle.FULL, enUS, "Saturday"}, + {DAY_OF_WEEK, 7, TextStyle.FULL, enUS, "Sunday"}, + + {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "Segunda-feira"}, + {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "Ter\u00E7a-feira"}, + {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "Quarta-feira"}, + {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "Quinta-feira"}, + {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "Sexta-feira"}, + {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "S\u00E1bado"}, + {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "Domingo"}, + + {MONTH_OF_YEAR, 1, TextStyle.SHORT, enUS, "Jan"}, + {MONTH_OF_YEAR, 2, TextStyle.SHORT, enUS, "Feb"}, + {MONTH_OF_YEAR, 3, TextStyle.SHORT, enUS, "Mar"}, + {MONTH_OF_YEAR, 4, TextStyle.SHORT, enUS, "Apr"}, + {MONTH_OF_YEAR, 5, TextStyle.SHORT, enUS, "May"}, + {MONTH_OF_YEAR, 6, TextStyle.SHORT, enUS, "Jun"}, + {MONTH_OF_YEAR, 7, TextStyle.SHORT, enUS, "Jul"}, + {MONTH_OF_YEAR, 8, TextStyle.SHORT, enUS, "Aug"}, + {MONTH_OF_YEAR, 9, TextStyle.SHORT, enUS, "Sep"}, + {MONTH_OF_YEAR, 10, TextStyle.SHORT, enUS, "Oct"}, + {MONTH_OF_YEAR, 11, TextStyle.SHORT, enUS, "Nov"}, + {MONTH_OF_YEAR, 12, TextStyle.SHORT, enUS, "Dec"}, + + {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "Jan"}, + {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "Fev"}, + {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "Mar"}, + {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "Abr"}, + {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "Mai"}, + {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "Jun"}, + {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "Jul"}, + {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "Ago"}, + {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "Set"}, + {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "Out"}, + {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "Nov"}, + {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "Dez"}, + + {MONTH_OF_YEAR, 1, TextStyle.FULL, enUS, "January"}, + {MONTH_OF_YEAR, 2, TextStyle.FULL, enUS, "February"}, + {MONTH_OF_YEAR, 3, TextStyle.FULL, enUS, "March"}, + {MONTH_OF_YEAR, 4, TextStyle.FULL, enUS, "April"}, + {MONTH_OF_YEAR, 5, TextStyle.FULL, enUS, "May"}, + {MONTH_OF_YEAR, 6, TextStyle.FULL, enUS, "June"}, + {MONTH_OF_YEAR, 7, TextStyle.FULL, enUS, "July"}, + {MONTH_OF_YEAR, 8, TextStyle.FULL, enUS, "August"}, + {MONTH_OF_YEAR, 9, TextStyle.FULL, enUS, "September"}, + {MONTH_OF_YEAR, 10, TextStyle.FULL, enUS, "October"}, + {MONTH_OF_YEAR, 11, TextStyle.FULL, enUS, "November"}, + {MONTH_OF_YEAR, 12, TextStyle.FULL, enUS, "December"}, + + {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "Janeiro"}, + {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "Fevereiro"}, + {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "Mar\u00E7o"}, + {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "Abril"}, + {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "Maio"}, + {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "Junho"}, + {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "Julho"}, + {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "Agosto"}, + {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "Setembro"}, + {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "Outubro"}, + {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "Novembro"}, + {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "Dezembro"}, + + {AMPM_OF_DAY, 0, TextStyle.SHORT, enUS, "AM"}, + {AMPM_OF_DAY, 1, TextStyle.SHORT, enUS, "PM"}, + + }; + } + + @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); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java b/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java new file mode 100644 index 00000000000..4be3b6cce46 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java @@ -0,0 +1,343 @@ +/* + * 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 java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static org.testng.Assert.assertEquals; +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.temporal.TemporalField; + +import test.java.time.temporal.MockFieldValue; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test FractionPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestFractionPrinterParser extends AbstractTestPrinterParser { + + private DateTimeFormatter getFormatter(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { + return builder.appendFraction(field, minWidth, maxWidth, decimalPoint).toFormatter(locale).withSymbols(symbols); + } + + //----------------------------------------------------------------------- + // print + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeException.class) + public void test_print_emptyCalendrical() throws Exception { + getFormatter(NANO_OF_SECOND, 0, 9, true).printTo(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); + assertEquals(buf.toString(), "EXISTING.000000003"); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Nanos") + Object[][] provider_nanos() { + return new Object[][] { + {0, 9, 0, ""}, + {0, 9, 2, ".000000002"}, + {0, 9, 20, ".00000002"}, + {0, 9, 200, ".0000002"}, + {0, 9, 2000, ".000002"}, + {0, 9, 20000, ".00002"}, + {0, 9, 200000, ".0002"}, + {0, 9, 2000000, ".002"}, + {0, 9, 20000000, ".02"}, + {0, 9, 200000000, ".2"}, + {0, 9, 1, ".000000001"}, + {0, 9, 12, ".000000012"}, + {0, 9, 123, ".000000123"}, + {0, 9, 1234, ".000001234"}, + {0, 9, 12345, ".000012345"}, + {0, 9, 123456, ".000123456"}, + {0, 9, 1234567, ".001234567"}, + {0, 9, 12345678, ".012345678"}, + {0, 9, 123456789, ".123456789"}, + + {1, 9, 0, ".0"}, + {1, 9, 2, ".000000002"}, + {1, 9, 20, ".00000002"}, + {1, 9, 200, ".0000002"}, + {1, 9, 2000, ".000002"}, + {1, 9, 20000, ".00002"}, + {1, 9, 200000, ".0002"}, + {1, 9, 2000000, ".002"}, + {1, 9, 20000000, ".02"}, + {1, 9, 200000000, ".2"}, + + {2, 3, 0, ".00"}, + {2, 3, 2, ".000"}, + {2, 3, 20, ".000"}, + {2, 3, 200, ".000"}, + {2, 3, 2000, ".000"}, + {2, 3, 20000, ".000"}, + {2, 3, 200000, ".000"}, + {2, 3, 2000000, ".002"}, + {2, 3, 20000000, ".02"}, + {2, 3, 200000000, ".20"}, + {2, 3, 1, ".000"}, + {2, 3, 12, ".000"}, + {2, 3, 123, ".000"}, + {2, 3, 1234, ".000"}, + {2, 3, 12345, ".000"}, + {2, 3, 123456, ".000"}, + {2, 3, 1234567, ".001"}, + {2, 3, 12345678, ".012"}, + {2, 3, 123456789, ".123"}, + + {6, 6, 0, ".000000"}, + {6, 6, 2, ".000000"}, + {6, 6, 20, ".000000"}, + {6, 6, 200, ".000000"}, + {6, 6, 2000, ".000002"}, + {6, 6, 20000, ".000020"}, + {6, 6, 200000, ".000200"}, + {6, 6, 2000000, ".002000"}, + {6, 6, 20000000, ".020000"}, + {6, 6, 200000000, ".200000"}, + {6, 6, 1, ".000000"}, + {6, 6, 12, ".000000"}, + {6, 6, 123, ".000000"}, + {6, 6, 1234, ".000001"}, + {6, 6, 12345, ".000012"}, + {6, 6, 123456, ".000123"}, + {6, 6, 1234567, ".001234"}, + {6, 6, 12345678, ".012345"}, + {6, 6, 123456789, ".123456"}, + }; + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), result); + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), (result.startsWith(".") ? result.substring(1) : result)); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Seconds") + Object[][] provider_seconds() { + return new Object[][] { + {0, 9, 0, ""}, + {0, 9, 3, ".05"}, + {0, 9, 6, ".1"}, + {0, 9, 9, ".15"}, + {0, 9, 12, ".2"}, + {0, 9, 15, ".25"}, + {0, 9, 30, ".5"}, + {0, 9, 45, ".75"}, + + {2, 2, 0, ".00"}, + {2, 2, 3, ".05"}, + {2, 2, 6, ".10"}, + {2, 2, 9, ".15"}, + {2, 2, 12, ".20"}, + {2, 2, 15, ".25"}, + {2, 2, 30, ".50"}, + {2, 2, 45, ".75"}, + }; + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), result); + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), (result.startsWith(".") ? result.substring(1) : result)); + } + + //----------------------------------------------------------------------- + // parse + //----------------------------------------------------------------------- + @Test(dataProvider="Nanos") + 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); + assertEquals(pos.getIndex(), result.length()); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), result.length()); + int expectedValue = fixParsedValue(maxWidth, value); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), result.length()); + assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + } + +// @Test(dataProvider="Nanos") +// public void test_reverseParse_followedByNonDigit_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception { +// FractionPrinterParser pp = new FractionPrinterParser(NANO_OF_SECOND, minWidth, maxWidth, false); +// int newPos = pp.parse(parseContext, result + " ", (result.startsWith(".") ? 1 : 0)); +// assertEquals(newPos, result.length()); +// int expectedValue = fixParsedValue(maxWidth, value); +// assertParsed(parseContext, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); +// } + + @Test(dataProvider="Nanos") + 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); + assertEquals(pos.getIndex(), result.length() + 1); + assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + } + + private int fixParsedValue(int maxWidth, int value) { + if (maxWidth < 9) { + int power = (int) Math.pow(10, (9 - maxWidth)); + value = (value / power) * power; + } + return value; + } + + @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); + assertEquals(pos.getIndex(), result.length()); + assertParsed(dtb, SECOND_OF_MINUTE, value == 0 && minWidth == 0 ? null : (long) value); + } + + private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) { + if (value == null) { + assertEquals(dtb.containsFieldValue(field), false); + } else { + assertEquals(dtb.getLong(field), (long)value); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="ParseNothing") + Object[][] provider_parseNothing() { + return new Object[][] { + {NANO_OF_SECOND, 3, 6, true, "", 0, 0}, + {NANO_OF_SECOND, 3, 6, true, "A", 0, 0}, + {NANO_OF_SECOND, 3, 6, true, ".", 0, 1}, + {NANO_OF_SECOND, 3, 6, true, ".5", 0, 1}, + {NANO_OF_SECOND, 3, 6, true, ".51", 0, 1}, + {NANO_OF_SECOND, 3, 6, true, ".A23456", 0, 1}, + {NANO_OF_SECOND, 3, 6, true, ".1A3456", 0, 1}, + }; + } + + @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); + assertEquals(ppos.getErrorIndex(), expected); + } + + //----------------------------------------------------------------------- + public void test_toString() throws Exception { + assertEquals(getFormatter(NANO_OF_SECOND, 3, 6, true).toString(), "Fraction(NanoOfSecond,3,6,DecimalPoint)"); + } + + public void test_toString_noDecimalPoint() throws Exception { + assertEquals(getFormatter(NANO_OF_SECOND, 3, 6, false).toString(), "Fraction(NanoOfSecond,3,6)"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestNumberParser.java b/jdk/test/java/time/test/java/time/format/TestNumberParser.java new file mode 100644 index 00000000000..af4b3b6e940 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestNumberParser.java @@ -0,0 +1,547 @@ +/* + * 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 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 java.text.ParsePosition; +import java.time.format.DateTimeBuilder; +import java.time.temporal.TemporalField; +import java.time.format.DateTimeFormatter; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test NumberPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestNumberParser extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", -1, IndexOutOfBoundsException.class}, + {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", 3, IndexOutOfBoundsException.class}, + }; + } + + @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); + } catch (RuntimeException ex) { + assertTrue(expected.isInstance(ex)); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseData") + Object[][] provider_parseData() { + return new Object[][] { + // normal + {1, 2, SignStyle.NEVER, 0, "12", 0, 2, 12L}, // normal + {1, 2, SignStyle.NEVER, 0, "Xxx12Xxx", 3, 5, 12L}, // parse in middle + {1, 2, SignStyle.NEVER, 0, "99912999", 3, 5, 12L}, // parse in middle + {2, 4, SignStyle.NEVER, 0, "12345", 0, 4, 1234L}, // stops at max width + {2, 4, SignStyle.NEVER, 0, "12-45", 0, 2, 12L}, // stops at dash + {2, 4, SignStyle.NEVER, 0, "123-5", 0, 3, 123L}, // stops at dash + {1, 10, SignStyle.NORMAL, 0, "2147483647", 0, 10, Integer.MAX_VALUE}, + {1, 10, SignStyle.NORMAL, 0, "-2147483648", 0, 11, Integer.MIN_VALUE}, + {1, 10, SignStyle.NORMAL, 0, "2147483648", 0, 10, 2147483648L}, + {1, 10, SignStyle.NORMAL, 0, "-2147483649", 0, 11, -2147483649L}, + {1, 10, SignStyle.NORMAL, 0, "987659876598765", 0, 10, 9876598765L}, + {1, 19, SignStyle.NORMAL, 0, "999999999999999999", 0, 18, 999999999999999999L}, + {1, 19, SignStyle.NORMAL, 0, "-999999999999999999", 0, 19, -999999999999999999L}, + {1, 19, SignStyle.NORMAL, 0, "1000000000000000000", 0, 19, 1000000000000000000L}, + {1, 19, SignStyle.NORMAL, 0, "-1000000000000000000", 0, 20, -1000000000000000000L}, + {1, 19, SignStyle.NORMAL, 0, "000000000000000000", 0, 18, 0L}, + {1, 19, SignStyle.NORMAL, 0, "0000000000000000000", 0, 19, 0L}, + {1, 19, SignStyle.NORMAL, 0, "9223372036854775807", 0, 19, Long.MAX_VALUE}, + {1, 19, SignStyle.NORMAL, 0, "-9223372036854775808", 0, 20, Long.MIN_VALUE}, + {1, 19, SignStyle.NORMAL, 0, "9223372036854775808", 0, 18, 922337203685477580L}, // last digit not parsed + {1, 19, SignStyle.NORMAL, 0, "-9223372036854775809", 0, 19, -922337203685477580L}, // last digit not parsed + // no match + {1, 2, SignStyle.NEVER, 1, "A1", 0, 0, 0}, + {1, 2, SignStyle.NEVER, 1, " 1", 0, 0, 0}, + {1, 2, SignStyle.NEVER, 1, " 1", 1, 1, 0}, + {2, 2, SignStyle.NEVER, 1, "1", 0, 0, 0}, + {2, 2, SignStyle.NEVER, 1, "Xxx1", 0, 0, 0}, + {2, 2, SignStyle.NEVER, 1, "1", 1, 1, 0}, + {2, 2, SignStyle.NEVER, 1, "Xxx1", 4, 4, 0}, + {2, 2, SignStyle.NEVER, 1, "1-2", 0, 0, 0}, + {1, 19, SignStyle.NORMAL, 0, "-000000000000000000", 0, 0, 0}, + {1, 19, SignStyle.NORMAL, 0, "-0000000000000000000", 0, 0, 0}, + // parse reserving space 1 (adjacent-parsing) + {1, 1, SignStyle.NEVER, 1, "12", 0, 1, 1L}, + {1, 19, SignStyle.NEVER, 1, "12", 0, 1, 1L}, + {1, 19, SignStyle.NEVER, 1, "12345", 0, 4, 1234L}, + {1, 19, SignStyle.NEVER, 1, "12345678901", 0, 10, 1234567890L}, + {1, 19, SignStyle.NEVER, 1, "123456789012345678901234567890", 0, 19, 1234567890123456789L}, + {1, 19, SignStyle.NEVER, 1, "1", 0, 1, 1L}, // error from next field + {2, 2, SignStyle.NEVER, 1, "12", 0, 2, 12L}, // error from next field + {2, 19, SignStyle.NEVER, 1, "1", 0, 0, 0}, + // parse reserving space 2 (adjacent-parsing) + {1, 1, SignStyle.NEVER, 2, "123", 0, 1, 1L}, + {1, 19, SignStyle.NEVER, 2, "123", 0, 1, 1L}, + {1, 19, SignStyle.NEVER, 2, "12345", 0, 3, 123L}, + {1, 19, SignStyle.NEVER, 2, "12345678901", 0, 9, 123456789L}, + {1, 19, SignStyle.NEVER, 2, "123456789012345678901234567890", 0, 19, 1234567890123456789L}, + {1, 19, SignStyle.NEVER, 2, "1", 0, 1, 1L}, // error from next field + {1, 19, SignStyle.NEVER, 2, "12", 0, 1, 1L}, // error from next field + {2, 2, SignStyle.NEVER, 2, "12", 0, 2, 12L}, // error from next field + {2, 19, SignStyle.NEVER, 2, "1", 0, 0, 0}, + {2, 19, SignStyle.NEVER, 2, "1AAAAABBBBBCCCCC", 0, 0, 0}, + }; + } + + //----------------------------------------------------------------------- + @Test(dataProvider="parseData") + public void test_parse_fresh(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) { + ParsePosition ppos = new ParsePosition(pos); + DateTimeFormatter dtf = getFormatter(DAY_OF_MONTH, minWidth, maxWidth, signStyle); + if (subsequentWidth > 0) { + // hacky, to reserve space + dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols); + } + DateTimeBuilder dtb = dtf.parseToBuilder(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); + } + } + + @Test(dataProvider="parseData") + public void test_parse_textField(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) { + ParsePosition ppos = new ParsePosition(pos); + DateTimeFormatter dtf = getFormatter(DAY_OF_WEEK, minWidth, maxWidth, signStyle); + if (subsequentWidth > 0) { + // hacky, to reserve space + dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols); + } + DateTimeBuilder dtb = dtf.parseToBuilder(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); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseSignsStrict") + Object[][] provider_parseSignsStrict() { + return new Object[][] { + // basics + {"0", 1, 2, SignStyle.NEVER, 1, 0}, + {"1", 1, 2, SignStyle.NEVER, 1, 1}, + {"2", 1, 2, SignStyle.NEVER, 1, 2}, + {"3", 1, 2, SignStyle.NEVER, 1, 3}, + {"4", 1, 2, SignStyle.NEVER, 1, 4}, + {"5", 1, 2, SignStyle.NEVER, 1, 5}, + {"6", 1, 2, SignStyle.NEVER, 1, 6}, + {"7", 1, 2, SignStyle.NEVER, 1, 7}, + {"8", 1, 2, SignStyle.NEVER, 1, 8}, + {"9", 1, 2, SignStyle.NEVER, 1, 9}, + {"10", 1, 2, SignStyle.NEVER, 2, 10}, + {"100", 1, 2, SignStyle.NEVER, 2, 10}, + {"100", 1, 3, SignStyle.NEVER, 3, 100}, + + // never + {"0", 1, 2, SignStyle.NEVER, 1, 0}, + {"5", 1, 2, SignStyle.NEVER, 1, 5}, + {"50", 1, 2, SignStyle.NEVER, 2, 50}, + {"500", 1, 2, SignStyle.NEVER, 2, 50}, + {"-0", 1, 2, SignStyle.NEVER, 0, null}, + {"-5", 1, 2, SignStyle.NEVER, 0, null}, + {"-50", 1, 2, SignStyle.NEVER, 0, null}, + {"-500", 1, 2, SignStyle.NEVER, 0, null}, + {"-AAA", 1, 2, SignStyle.NEVER, 0, null}, + {"+0", 1, 2, SignStyle.NEVER, 0, null}, + {"+5", 1, 2, SignStyle.NEVER, 0, null}, + {"+50", 1, 2, SignStyle.NEVER, 0, null}, + {"+500", 1, 2, SignStyle.NEVER, 0, null}, + {"+AAA", 1, 2, SignStyle.NEVER, 0, null}, + + // not negative + {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0}, + {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5}, + {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50}, + {"500", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50}, + {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null}, + + // normal + {"0", 1, 2, SignStyle.NORMAL, 1, 0}, + {"5", 1, 2, SignStyle.NORMAL, 1, 5}, + {"50", 1, 2, SignStyle.NORMAL, 2, 50}, + {"500", 1, 2, SignStyle.NORMAL, 2, 50}, + {"-0", 1, 2, SignStyle.NORMAL, 0, null}, + {"-5", 1, 2, SignStyle.NORMAL, 2, -5}, + {"-50", 1, 2, SignStyle.NORMAL, 3, -50}, + {"-500", 1, 2, SignStyle.NORMAL, 3, -50}, + {"-AAA", 1, 2, SignStyle.NORMAL, 1, null}, + {"+0", 1, 2, SignStyle.NORMAL, 0, null}, + {"+5", 1, 2, SignStyle.NORMAL, 0, null}, + {"+50", 1, 2, SignStyle.NORMAL, 0, null}, + {"+500", 1, 2, SignStyle.NORMAL, 0, null}, + {"+AAA", 1, 2, SignStyle.NORMAL, 0, null}, + + // always + {"0", 1, 2, SignStyle.ALWAYS, 0, null}, + {"5", 1, 2, SignStyle.ALWAYS, 0, null}, + {"50", 1, 2, SignStyle.ALWAYS, 0, null}, + {"500", 1, 2, SignStyle.ALWAYS, 0, null}, + {"-0", 1, 2, SignStyle.ALWAYS, 0, null}, + {"-5", 1, 2, SignStyle.ALWAYS, 2, -5}, + {"-50", 1, 2, SignStyle.ALWAYS, 3, -50}, + {"-500", 1, 2, SignStyle.ALWAYS, 3, -50}, + {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null}, + {"+0", 1, 2, SignStyle.ALWAYS, 2, 0}, + {"+5", 1, 2, SignStyle.ALWAYS, 2, 5}, + {"+50", 1, 2, SignStyle.ALWAYS, 3, 50}, + {"+500", 1, 2, SignStyle.ALWAYS, 3, 50}, + {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null}, + + // exceeds pad + {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0}, + {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5}, + {"50", 1, 2, SignStyle.EXCEEDS_PAD, 0, null}, + {"500", 1, 2, SignStyle.EXCEEDS_PAD, 0, null}, + {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null}, + {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5}, + {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50}, + {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50}, + {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null}, + {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null}, + {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 0, null}, + {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50}, + {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50}, + {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null}, + }; + } + + @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); + if (pos.getErrorIndex() != -1) { + assertEquals(pos.getErrorIndex(), parseLen); + } else { + assertEquals(pos.getIndex(), parseLen); + assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseSignsLenient") + Object[][] provider_parseSignsLenient() { + return new Object[][] { + // never + {"0", 1, 2, SignStyle.NEVER, 1, 0}, + {"5", 1, 2, SignStyle.NEVER, 1, 5}, + {"50", 1, 2, SignStyle.NEVER, 2, 50}, + {"500", 1, 2, SignStyle.NEVER, 2, 50}, + {"-0", 1, 2, SignStyle.NEVER, 2, 0}, + {"-5", 1, 2, SignStyle.NEVER, 2, -5}, + {"-50", 1, 2, SignStyle.NEVER, 3, -50}, + {"-500", 1, 2, SignStyle.NEVER, 3, -50}, + {"-AAA", 1, 2, SignStyle.NEVER, 1, null}, + {"+0", 1, 2, SignStyle.NEVER, 2, 0}, + {"+5", 1, 2, SignStyle.NEVER, 2, 5}, + {"+50", 1, 2, SignStyle.NEVER, 3, 50}, + {"+500", 1, 2, SignStyle.NEVER, 3, 50}, + {"+AAA", 1, 2, SignStyle.NEVER, 1, null}, + {"50", 2, 2, SignStyle.NEVER, 2, 50}, + {"-50", 2, 2, SignStyle.NEVER, 0, null}, + {"+50", 2, 2, SignStyle.NEVER, 0, null}, + + // not negative + {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0}, + {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5}, + {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50}, + {"500", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50}, + {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0}, + {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 2, -5}, + {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 3, -50}, + {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 3, -50}, + {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null}, + {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0}, + {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 2, 5}, + {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 3, 50}, + {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 3, 50}, + {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null}, + {"50", 2, 2, SignStyle.NOT_NEGATIVE, 2, 50}, + {"-50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null}, + {"+50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null}, + + // normal + {"0", 1, 2, SignStyle.NORMAL, 1, 0}, + {"5", 1, 2, SignStyle.NORMAL, 1, 5}, + {"50", 1, 2, SignStyle.NORMAL, 2, 50}, + {"500", 1, 2, SignStyle.NORMAL, 2, 50}, + {"-0", 1, 2, SignStyle.NORMAL, 2, 0}, + {"-5", 1, 2, SignStyle.NORMAL, 2, -5}, + {"-50", 1, 2, SignStyle.NORMAL, 3, -50}, + {"-500", 1, 2, SignStyle.NORMAL, 3, -50}, + {"-AAA", 1, 2, SignStyle.NORMAL, 1, null}, + {"+0", 1, 2, SignStyle.NORMAL, 2, 0}, + {"+5", 1, 2, SignStyle.NORMAL, 2, 5}, + {"+50", 1, 2, SignStyle.NORMAL, 3, 50}, + {"+500", 1, 2, SignStyle.NORMAL, 3, 50}, + {"+AAA", 1, 2, SignStyle.NORMAL, 1, null}, + {"50", 2, 2, SignStyle.NORMAL, 2, 50}, + {"-50", 2, 2, SignStyle.NORMAL, 3, -50}, + {"+50", 2, 2, SignStyle.NORMAL, 3, 50}, + + // always + {"0", 1, 2, SignStyle.ALWAYS, 1, 0}, + {"5", 1, 2, SignStyle.ALWAYS, 1, 5}, + {"50", 1, 2, SignStyle.ALWAYS, 2, 50}, + {"500", 1, 2, SignStyle.ALWAYS, 2, 50}, + {"-0", 1, 2, SignStyle.ALWAYS, 2, 0}, + {"-5", 1, 2, SignStyle.ALWAYS, 2, -5}, + {"-50", 1, 2, SignStyle.ALWAYS, 3, -50}, + {"-500", 1, 2, SignStyle.ALWAYS, 3, -50}, + {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null}, + {"+0", 1, 2, SignStyle.ALWAYS, 2, 0}, + {"+5", 1, 2, SignStyle.ALWAYS, 2, 5}, + {"+50", 1, 2, SignStyle.ALWAYS, 3, 50}, + {"+500", 1, 2, SignStyle.ALWAYS, 3, 50}, + {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null}, + + // exceeds pad + {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0}, + {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5}, + {"50", 1, 2, SignStyle.EXCEEDS_PAD, 2, 50}, + {"500", 1, 2, SignStyle.EXCEEDS_PAD, 2, 50}, + {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0}, + {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5}, + {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50}, + {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50}, + {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null}, + {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0}, + {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 2, 5}, + {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50}, + {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50}, + {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null}, + }; + } + + @Test(dataProvider="parseSignsLenient") + 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); + if (pos.getErrorIndex() != -1) { + assertEquals(pos.getErrorIndex(), parseLen); + } else { + assertEquals(pos.getIndex(), parseLen); + assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseDigitsLenient") + Object[][] provider_parseDigitsLenient() { + return new Object[][] { + // never + {"5", 1, 2, SignStyle.NEVER, 1, 5}, + {"5", 2, 2, SignStyle.NEVER, 1, 5}, + {"54", 1, 3, SignStyle.NEVER, 2, 54}, + {"54", 2, 3, SignStyle.NEVER, 2, 54}, + {"54", 3, 3, SignStyle.NEVER, 2, 54}, + {"543", 1, 3, SignStyle.NEVER, 3, 543}, + {"543", 2, 3, SignStyle.NEVER, 3, 543}, + {"543", 3, 3, SignStyle.NEVER, 3, 543}, + {"5432", 1, 3, SignStyle.NEVER, 3, 543}, + {"5432", 2, 3, SignStyle.NEVER, 3, 543}, + {"5432", 3, 3, SignStyle.NEVER, 3, 543}, + {"5AAA", 2, 3, SignStyle.NEVER, 1, 5}, + + // not negative + {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5}, + {"5", 2, 2, SignStyle.NOT_NEGATIVE, 1, 5}, + {"54", 1, 3, SignStyle.NOT_NEGATIVE, 2, 54}, + {"54", 2, 3, SignStyle.NOT_NEGATIVE, 2, 54}, + {"54", 3, 3, SignStyle.NOT_NEGATIVE, 2, 54}, + {"543", 1, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"543", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"543", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"5432", 1, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"5432", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"5432", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543}, + {"5AAA", 2, 3, SignStyle.NOT_NEGATIVE, 1, 5}, + + // normal + {"5", 1, 2, SignStyle.NORMAL, 1, 5}, + {"5", 2, 2, SignStyle.NORMAL, 1, 5}, + {"54", 1, 3, SignStyle.NORMAL, 2, 54}, + {"54", 2, 3, SignStyle.NORMAL, 2, 54}, + {"54", 3, 3, SignStyle.NORMAL, 2, 54}, + {"543", 1, 3, SignStyle.NORMAL, 3, 543}, + {"543", 2, 3, SignStyle.NORMAL, 3, 543}, + {"543", 3, 3, SignStyle.NORMAL, 3, 543}, + {"5432", 1, 3, SignStyle.NORMAL, 3, 543}, + {"5432", 2, 3, SignStyle.NORMAL, 3, 543}, + {"5432", 3, 3, SignStyle.NORMAL, 3, 543}, + {"5AAA", 2, 3, SignStyle.NORMAL, 1, 5}, + + // always + {"5", 1, 2, SignStyle.ALWAYS, 1, 5}, + {"5", 2, 2, SignStyle.ALWAYS, 1, 5}, + {"54", 1, 3, SignStyle.ALWAYS, 2, 54}, + {"54", 2, 3, SignStyle.ALWAYS, 2, 54}, + {"54", 3, 3, SignStyle.ALWAYS, 2, 54}, + {"543", 1, 3, SignStyle.ALWAYS, 3, 543}, + {"543", 2, 3, SignStyle.ALWAYS, 3, 543}, + {"543", 3, 3, SignStyle.ALWAYS, 3, 543}, + {"5432", 1, 3, SignStyle.ALWAYS, 3, 543}, + {"5432", 2, 3, SignStyle.ALWAYS, 3, 543}, + {"5432", 3, 3, SignStyle.ALWAYS, 3, 543}, + {"5AAA", 2, 3, SignStyle.ALWAYS, 1, 5}, + + // exceeds pad + {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5}, + {"5", 2, 2, SignStyle.EXCEEDS_PAD, 1, 5}, + {"54", 1, 3, SignStyle.EXCEEDS_PAD, 2, 54}, + {"54", 2, 3, SignStyle.EXCEEDS_PAD, 2, 54}, + {"54", 3, 3, SignStyle.EXCEEDS_PAD, 2, 54}, + {"543", 1, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"543", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"543", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"5432", 1, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"5432", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"5432", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543}, + {"5AAA", 2, 3, SignStyle.EXCEEDS_PAD, 1, 5}, + }; + } + + @Test(dataProvider="parseDigitsLenient") + 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); + if (pos.getErrorIndex() != -1) { + assertEquals(pos.getErrorIndex(), parseLen); + } else { + assertEquals(pos.getIndex(), parseLen); + assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseDigitsAdjacentLenient") + Object[][] provider_parseDigitsAdjacentLenient() { + return new Object[][] { + // never + {"5", 1, null, null}, + {"54", 1, null, null}, + + {"543", 3, 5, 43}, + {"543A", 3, 5, 43}, + + {"5432", 4, 54, 32}, + {"5432A", 4, 54, 32}, + + {"54321", 4, 54, 32}, + {"54321A", 4, 54, 32}, + }; + } + + @Test(dataProvider="parseDigitsAdjacentLenient") + public void test_parseDigitsAdjacentLenient(String input, int parseLen, Integer parseMonth, Integer parsedDay) throws Exception { + setStrict(false); + ParsePosition pos = new ParsePosition(0); + 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); + 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); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java new file mode 100644 index 00000000000..80c05b8eb9f --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java @@ -0,0 +1,283 @@ +/* + * 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 java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.time.DateTimeException; +import java.time.LocalDate; +import test.java.time.temporal.MockFieldValue; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test SimpleNumberPrinterParser. + */ +@Test +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); + } + + 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); + assertEquals(buf.toString(), "EXISTING3"); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Pad") + Object[][] provider_pad() { + return new Object[][] { + {1, 1, -10, null}, + {1, 1, -9, "9"}, + {1, 1, -1, "1"}, + {1, 1, 0, "0"}, + {1, 1, 3, "3"}, + {1, 1, 9, "9"}, + {1, 1, 10, null}, + + {1, 2, -100, null}, + {1, 2, -99, "99"}, + {1, 2, -10, "10"}, + {1, 2, -9, "9"}, + {1, 2, -1, "1"}, + {1, 2, 0, "0"}, + {1, 2, 3, "3"}, + {1, 2, 9, "9"}, + {1, 2, 10, "10"}, + {1, 2, 99, "99"}, + {1, 2, 100, null}, + + {2, 2, -100, null}, + {2, 2, -99, "99"}, + {2, 2, -10, "10"}, + {2, 2, -9, "09"}, + {2, 2, -1, "01"}, + {2, 2, 0, "00"}, + {2, 2, 3, "03"}, + {2, 2, 9, "09"}, + {2, 2, 10, "10"}, + {2, 2, 99, "99"}, + {2, 2, 100, null}, + + {1, 3, -1000, null}, + {1, 3, -999, "999"}, + {1, 3, -100, "100"}, + {1, 3, -99, "99"}, + {1, 3, -10, "10"}, + {1, 3, -9, "9"}, + {1, 3, -1, "1"}, + {1, 3, 0, "0"}, + {1, 3, 3, "3"}, + {1, 3, 9, "9"}, + {1, 3, 10, "10"}, + {1, 3, 99, "99"}, + {1, 3, 100, "100"}, + {1, 3, 999, "999"}, + {1, 3, 1000, null}, + + {2, 3, -1000, null}, + {2, 3, -999, "999"}, + {2, 3, -100, "100"}, + {2, 3, -99, "99"}, + {2, 3, -10, "10"}, + {2, 3, -9, "09"}, + {2, 3, -1, "01"}, + {2, 3, 0, "00"}, + {2, 3, 3, "03"}, + {2, 3, 9, "09"}, + {2, 3, 10, "10"}, + {2, 3, 99, "99"}, + {2, 3, 100, "100"}, + {2, 3, 999, "999"}, + {2, 3, 1000, null}, + + {3, 3, -1000, null}, + {3, 3, -999, "999"}, + {3, 3, -100, "100"}, + {3, 3, -99, "099"}, + {3, 3, -10, "010"}, + {3, 3, -9, "009"}, + {3, 3, -1, "001"}, + {3, 3, 0, "000"}, + {3, 3, 3, "003"}, + {3, 3, 9, "009"}, + {3, 3, 10, "010"}, + {3, 3, 99, "099"}, + {3, 3, 100, "100"}, + {3, 3, 999, "999"}, + {3, 3, 1000, null}, + + {1, 10, Integer.MAX_VALUE - 1, "2147483646"}, + {1, 10, Integer.MAX_VALUE, "2147483647"}, + {1, 10, Integer.MIN_VALUE + 1, "2147483647"}, + {1, 10, Integer.MIN_VALUE, "2147483648"}, + }; + } + + @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); + if (result == null || value < 0) { + fail("Expected exception"); + } + assertEquals(buf.toString(), result); + } catch (DateTimePrintException ex) { + if (result == null || value < 0) { + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + } else { + throw ex; + } + } + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), result); + } catch (DateTimePrintException ex) { + if (result != null) { + throw ex; + } + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + } + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), (value < 0 ? "-" + result : result)); + } catch (DateTimePrintException ex) { + if (result != null) { + throw ex; + } + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + } + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), (value < 0 ? "-" + result : "+" + result)); + } catch (DateTimePrintException ex) { + if (result != null) { + throw ex; + } + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + } + } + + @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); + if (result == null) { + fail("Expected exception"); + return; // unreachable + } + if (result.length() > minPad || value < 0) { + result = (value < 0 ? "-" + result : "+" + result); + } + assertEquals(buf.toString(), result); + } catch (DateTimePrintException ex) { + if (result != null) { + throw ex; + } + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + } + } + + //----------------------------------------------------------------------- + public void test_toString1() throws Exception { + assertEquals(getFormatter(HOUR_OF_DAY, 1, 19, SignStyle.NORMAL).toString(), "Value(HourOfDay)"); + } + + public void test_toString2() throws Exception { + assertEquals(getFormatter(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE).toString(), "Value(HourOfDay,2)"); + } + + public void test_toString3() throws Exception { + assertEquals(getFormatter(HOUR_OF_DAY, 1, 2, SignStyle.NOT_NEGATIVE).toString(), "Value(HourOfDay,1,2,NOT_NEGATIVE)"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java b/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java new file mode 100644 index 00000000000..08a9e24544d --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java @@ -0,0 +1,140 @@ +/* + * 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 java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.testng.Assert.assertEquals; + +import java.text.ParsePosition; +import java.time.format.DateTimeBuilder; + +import org.testng.annotations.Test; + +/** + * Test PadPrinterParserDecorator. + */ +@Test(groups={"implementation"}) +public class TestPadParserDecorator extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @Test(expectedExceptions=IndexOutOfBoundsException.class) + public void test_parse_negativePosition() throws Exception { + builder.padNext(3, '-').appendLiteral('Z'); + getFormatter().parseToBuilder("--Z", 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() 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); + } + + 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); + } + + 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); + assertEquals(pos.getErrorIndex(), 0); + } + + 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); + } + + //----------------------------------------------------------------------- + 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); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java b/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java new file mode 100644 index 00000000000..d6302aee4d7 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java @@ -0,0 +1,138 @@ +/* + * 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 java.time.LocalDate; + +import org.testng.annotations.Test; + +/** + * Test PadPrinterDecorator. + */ +@Test(groups={"implementation"}) +public class TestPadPrinterDecorator extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + public void test_print_emptyCalendrical() throws Exception { + builder.padNext(3, '-').appendLiteral('Z'); + getFormatter().printTo(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); + assertEquals(buf.toString(), "--Z"); + } + + public void test_print_append() throws Exception { + buf.append("EXISTING"); + builder.padNext(3, '-').appendLiteral('Z'); + getFormatter().printTo(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); + assertEquals(buf.toString(), "Z"); + } + + public void test_print_padRequiredSingle() throws Exception { + builder.padNext(5, '-').appendLiteral('Z'); + getFormatter().printTo(EMPTY_DTA, buf); + assertEquals(buf.toString(), "----Z"); + } + + public void test_print_noPadRequiredMultiple() throws Exception { + builder.padNext(4, '-').appendLiteral("WXYZ"); + getFormatter().printTo(EMPTY_DTA, buf); + assertEquals(buf.toString(), "WXYZ"); + } + + public void test_print_padRequiredMultiple() throws Exception { + builder.padNext(5, '-').appendLiteral("WXYZ"); + getFormatter().printTo(EMPTY_DTA, buf); + assertEquals(buf.toString(), "-WXYZ"); + } + + @Test(expectedExceptions=DateTimePrintException.class) + public void test_print_overPad() throws Exception { + builder.padNext(3, '-').appendLiteral("WXYZ"); + getFormatter().printTo(EMPTY_DTA, buf); + } + + //----------------------------------------------------------------------- + public void test_toString1() throws Exception { + builder.padNext(5, ' ').appendLiteral('Y'); + assertEquals(getFormatter().toString(), "Pad('Y',5)"); + } + + public void test_toString2() throws Exception { + builder.padNext(5, '-').appendLiteral('Y'); + assertEquals(getFormatter().toString(), "Pad('Y',5,'-')"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestReducedParser.java b/jdk/test/java/time/test/java/time/format/TestReducedParser.java new file mode 100644 index 00000000000..bcd383039ff --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestReducedParser.java @@ -0,0 +1,198 @@ +/* + * 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 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.temporal.TemporalField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ReducedPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestReducedParser extends AbstractTestPrinterParser { + + private DateTimeFormatter getFormatter0(TemporalField field, int width, int baseValue) { + return builder.appendValueReduced(field, width, baseValue).toFormatter(locale).withSymbols(symbols); + } + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {YEAR, 2, 2010, "12", -1, IndexOutOfBoundsException.class}, + {YEAR, 2, 2010, "12", 3, IndexOutOfBoundsException.class}, + }; + } + + @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)); + } catch (RuntimeException ex) { + assertTrue(expected.isInstance(ex)); + } + } + + //----------------------------------------------------------------------- + public void test_parse_fieldRangeIgnored() throws Exception { + ParsePosition pos = new ParsePosition(0); + DateTimeBuilder dtb = getFormatter0(DAY_OF_YEAR, 3, 10).parseToBuilder("456", pos); + assertEquals(pos.getIndex(), 3); + assertParsed(dtb, DAY_OF_YEAR, 456L); // parsed dayOfYear=456 + } + + //----------------------------------------------------------------------- + @DataProvider(name="Parse") + Object[][] provider_parse() { + return new Object[][] { + // negative zero + {YEAR, 1, 2010, "-0", 0, 0, null}, + + // general + {YEAR, 2, 2010, "Xxx12Xxx", 3, 5, 2012}, + {YEAR, 2, 2010, "12345", 0, 2, 2012}, + {YEAR, 2, 2010, "12-45", 0, 2, 2012}, + + // insufficient digits + {YEAR, 2, 2010, "0", 0, 0, null}, + {YEAR, 2, 2010, "1", 0, 0, null}, + {YEAR, 2, 2010, "1", 1, 1, null}, + {YEAR, 2, 2010, "1-2", 0, 0, null}, + {YEAR, 2, 2010, "9", 0, 0, null}, + + // other junk + {YEAR, 2, 2010, "A0", 0, 0, null}, + {YEAR, 2, 2010, "0A", 0, 0, null}, + {YEAR, 2, 2010, " 1", 0, 0, null}, + {YEAR, 2, 2010, "-1", 0, 0, null}, + {YEAR, 2, 2010, "-10", 0, 0, null}, + + // parse OK 1 + {YEAR, 1, 2010, "0", 0, 1, 2010}, + {YEAR, 1, 2010, "9", 0, 1, 2019}, + {YEAR, 1, 2010, "10", 0, 1, 2011}, + + {YEAR, 1, 2005, "0", 0, 1, 2010}, + {YEAR, 1, 2005, "4", 0, 1, 2014}, + {YEAR, 1, 2005, "5", 0, 1, 2005}, + {YEAR, 1, 2005, "9", 0, 1, 2009}, + {YEAR, 1, 2005, "10", 0, 1, 2011}, + + // parse OK 2 + {YEAR, 2, 2010, "00", 0, 2, 2100}, + {YEAR, 2, 2010, "09", 0, 2, 2109}, + {YEAR, 2, 2010, "10", 0, 2, 2010}, + {YEAR, 2, 2010, "99", 0, 2, 2099}, + {YEAR, 2, 2010, "100", 0, 2, 2010}, + + // parse OK 2 + {YEAR, 2, -2005, "05", 0, 2, -2005}, + {YEAR, 2, -2005, "00", 0, 2, -2000}, + {YEAR, 2, -2005, "99", 0, 2, -1999}, + {YEAR, 2, -2005, "06", 0, 2, -1906}, + {YEAR, 2, -2005, "100", 0, 2, -1910}, + }; + } + + @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); + if (ppos.getErrorIndex() != -1) { + assertEquals(ppos.getErrorIndex(), parseLen); + } else { + assertEquals(ppos.getIndex(), parseLen); + assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null); + } + } + + @Test(dataProvider="Parse") + 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); + if (ppos.getErrorIndex() != -1) { + assertEquals(ppos.getErrorIndex(), parseLen); + } else { + assertEquals(ppos.getIndex(), parseLen); + assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null); + } + } + + private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) { + if (value == null) { + assertEquals(dtb, null); + } else { + assertEquals(dtb.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 new file mode 100644 index 00000000000..698496dc57e --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java @@ -0,0 +1,181 @@ +/* + * 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 test.java.time.format; + +import java.time.format.*; + +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.temporal.TemporalField; +import test.java.time.temporal.MockFieldValue; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ReducedPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestReducedPrinter extends AbstractTestPrinterParser { + + private DateTimeFormatter getFormatter0(TemporalField field, int width, int baseValue) { + return builder.appendValueReduced(field, width, baseValue).toFormatter(locale).withSymbols(symbols); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeException.class) + public void test_print_emptyCalendrical() throws Exception { + getFormatter0(YEAR, 2, 2010).printTo(EMPTY_DTA, buf); + } + + //----------------------------------------------------------------------- + public void test_print_append() throws Exception { + buf.append("EXISTING"); + getFormatter0(YEAR, 2, 2010).printTo(LocalDate.of(2012, 1, 1), buf); + assertEquals(buf.toString(), "EXISTING12"); + } + + //----------------------------------------------------------------------- + @DataProvider(name="Pivot") + Object[][] provider_pivot() { + return new Object[][] { + {1, 2010, 2010, "0"}, + {1, 2010, 2011, "1"}, + {1, 2010, 2012, "2"}, + {1, 2010, 2013, "3"}, + {1, 2010, 2014, "4"}, + {1, 2010, 2015, "5"}, + {1, 2010, 2016, "6"}, + {1, 2010, 2017, "7"}, + {1, 2010, 2018, "8"}, + {1, 2010, 2019, "9"}, + {1, 2010, 2009, "9"}, + {1, 2010, 2020, "0"}, + + {2, 2010, 2010, "10"}, + {2, 2010, 2011, "11"}, + {2, 2010, 2021, "21"}, + {2, 2010, 2099, "99"}, + {2, 2010, 2100, "00"}, + {2, 2010, 2109, "09"}, + {2, 2010, 2009, "09"}, + {2, 2010, 2110, "10"}, + + {2, 2005, 2005, "05"}, + {2, 2005, 2099, "99"}, + {2, 2005, 2100, "00"}, + {2, 2005, 2104, "04"}, + {2, 2005, 2004, "04"}, + {2, 2005, 2105, "05"}, + + {3, 2005, 2005, "005"}, + {3, 2005, 2099, "099"}, + {3, 2005, 2100, "100"}, + {3, 2005, 2999, "999"}, + {3, 2005, 3000, "000"}, + {3, 2005, 3004, "004"}, + {3, 2005, 2004, "004"}, + {3, 2005, 3005, "005"}, + + {9, 2005, 2005, "000002005"}, + {9, 2005, 2099, "000002099"}, + {9, 2005, 2100, "000002100"}, + {9, 2005, 999999999, "999999999"}, + {9, 2005, 1000000000, "000000000"}, + {9, 2005, 1000002004, "000002004"}, + {9, 2005, 2004, "000002004"}, + {9, 2005, 1000002005, "000002005"}, + + {2, -2005, -2005, "05"}, + {2, -2005, -2000, "00"}, + {2, -2005, -1999, "99"}, + {2, -2005, -1904, "04"}, + {2, -2005, -2006, "06"}, + {2, -2005, -1905, "05"}, + }; + } + + @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); + if (result == null) { + fail("Expected exception"); + } + assertEquals(buf.toString(), result); + } catch (DateTimePrintException ex) { + if (result == null || value < 0) { + assertEquals(ex.getMessage().contains(YEAR.getName()), true); + } else { + throw ex; + } + } + } + + //----------------------------------------------------------------------- + public void test_toString() throws Exception { + assertEquals(getFormatter0(YEAR, 2, 2005).toString(), "ReducedValue(Year,2,2005)"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestSettingsParser.java b/jdk/test/java/time/test/java/time/format/TestSettingsParser.java new file mode 100644 index 00000000000..4b639aa56d4 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestSettingsParser.java @@ -0,0 +1,147 @@ +/* + * 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 java.time.format.*; + +import static org.testng.Assert.assertEquals; + +import java.text.ParsePosition; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test SettingsParser. + */ +@Test(groups={"implementation"}) +public class TestSettingsParser extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + public void test_print_sensitive() throws Exception { + setCaseSensitive(true); + getFormatter().printTo(dta, buf); + assertEquals(buf.toString(), ""); + } + + public void test_print_strict() throws Exception { + setStrict(true); + getFormatter().printTo(dta, buf); + assertEquals(buf.toString(), ""); + } + + /* + public void test_print_nulls() throws Exception { + setCaseSensitive(true); + getFormatter().printTo(null, null); + } + */ + + //----------------------------------------------------------------------- + public void test_parse_changeStyle_sensitive() throws Exception { + setCaseSensitive(true); + ParsePosition pos = new ParsePosition(0); + getFormatter().parseToBuilder("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); + assertEquals(pos.getIndex(), 0); + } + + public void test_parse_changeStyle_strict() throws Exception { + setStrict(true); + ParsePosition pos = new ParsePosition(0); + getFormatter().parseToBuilder("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); + assertEquals(pos.getIndex(), 0); + } + + //----------------------------------------------------------------------- + public void test_toString_sensitive() throws Exception { + setCaseSensitive(true); + assertEquals(getFormatter().toString(), "ParseCaseSensitive(true)"); + } + + public void test_toString_insensitive() throws Exception { + setCaseSensitive(false); + assertEquals(getFormatter().toString(), "ParseCaseSensitive(false)"); + } + + public void test_toString_strict() throws Exception { + setStrict(true); + assertEquals(getFormatter().toString(), "ParseStrict(true)"); + } + + public void test_toString_lenient() throws Exception { + setStrict(false); + assertEquals(getFormatter().toString(), "ParseStrict(false)"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java b/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java new file mode 100644 index 00000000000..bd67eab39f3 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java @@ -0,0 +1,137 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.time.format.DateTimeBuilder; +import java.text.ParsePosition; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test StringLiteralPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestStringLiteralParser extends AbstractTestPrinterParser { + + @DataProvider(name="success") + Object[][] data_success() { + return new Object[][] { + // match + {"hello", true, "hello", 0, 5}, + {"hello", true, "helloOTHER", 0, 5}, + {"hello", true, "OTHERhelloOTHER", 5, 10}, + {"hello", true, "OTHERhello", 5, 10}, + + // no match + {"hello", true, "", 0, 0}, + {"hello", true, "a", 1, 1}, + {"hello", true, "HELLO", 0, 0}, + {"hello", true, "hlloo", 0, 0}, + {"hello", true, "OTHERhllooOTHER", 5, 5}, + {"hello", true, "OTHERhlloo", 5, 5}, + {"hello", true, "h", 0, 0}, + {"hello", true, "OTHERh", 5, 5}, + + // case insensitive + {"hello", false, "hello", 0, 5}, + {"hello", false, "HELLO", 0, 5}, + {"hello", false, "HelLo", 0, 5}, + {"hello", false, "HelLO", 0, 5}, + }; + } + + @Test(dataProvider="success") + 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); + if (ppos.getErrorIndex() != -1) { + assertEquals(ppos.getIndex(), expectedPos); + } else { + assertEquals(ppos.getIndex(), expectedPos); + assertEquals(result.getCalendricalList().size(), 0); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {"hello", "hello", -1, IndexOutOfBoundsException.class}, + {"hello", "hello", 6, IndexOutOfBoundsException.class}, + }; + } + + @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); + } 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 new file mode 100644 index 00000000000..df018701b3c --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java @@ -0,0 +1,104 @@ +/* + * 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 org.testng.annotations.Test; + +/** + * Test StringLiteralPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestStringLiteralPrinter extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + public void test_print_emptyCalendrical() throws Exception { + buf.append("EXISTING"); + getFormatter("hello").printTo(EMPTY_DTA, buf); + assertEquals(buf.toString(), "EXISTINGhello"); + } + + public void test_print_dateTime() throws Exception { + buf.append("EXISTING"); + getFormatter("hello").printTo(dta, buf); + assertEquals(buf.toString(), "EXISTINGhello"); + } + + + + + public void test_print_emptyAppendable() throws Exception { + getFormatter("hello").printTo(dta, buf); + assertEquals(buf.toString(), "hello"); + } + + //----------------------------------------------------------------------- + public void test_toString() throws Exception { + assertEquals(getFormatter("hello").toString(), "'hello'"); + } + + public void test_toString_apos() throws Exception { + assertEquals(getFormatter("o'clock").toString(), "'o''clock'"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestTextParser.java b/jdk/test/java/time/test/java/time/format/TestTextParser.java new file mode 100644 index 00000000000..7961b27ac8b --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java @@ -0,0 +1,341 @@ +/* + * 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 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 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.temporal.TemporalField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test TextPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestTextParser extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {DAY_OF_WEEK, TextStyle.FULL, "Monday", -1, IndexOutOfBoundsException.class}, + {DAY_OF_WEEK, TextStyle.FULL, "Monday", 7, IndexOutOfBoundsException.class}, + }; + } + + @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)); + } catch (RuntimeException ex) { + assertTrue(expected.isInstance(ex)); + } + } + + //----------------------------------------------------------------------- + public void test_parse_midStr() throws Exception { + ParsePosition pos = new ParsePosition(3); + assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.FULL) + .parseToBuilder("XxxMondayXxx", pos) + .getLong(DAY_OF_WEEK), 1L); + assertEquals(pos.getIndex(), 9); + } + + public void test_parse_remainderIgnored() throws Exception { + ParsePosition pos = new ParsePosition(0); + assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.SHORT) + .parseToBuilder("Wednesday", pos) + .getLong(DAY_OF_WEEK), 3L); + assertEquals(pos.getIndex(), 3); + } + + //----------------------------------------------------------------------- + public void test_parse_noMatch1() throws Exception { + ParsePosition pos = new ParsePosition(0); + DateTimeBuilder dtb = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Munday", pos); + assertEquals(pos.getErrorIndex(), 0); + } + + public void test_parse_noMatch2() throws Exception { + ParsePosition pos = new ParsePosition(3); + DateTimeBuilder dtb = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos); + assertEquals(pos.getErrorIndex(), 3); + } + + public void test_parse_noMatch_atEnd() throws Exception { + ParsePosition pos = new ParsePosition(6); + DateTimeBuilder dtb = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos); + assertEquals(pos.getErrorIndex(), 6); + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseText") + Object[][] provider_text() { + return new Object[][] { + {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"}, + {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"}, + {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"}, + {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"}, + {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"}, + + {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"}, + {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"}, + {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"}, + {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"}, + {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"}, + {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"}, + {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"}, + + {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"}, + {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"}, + + {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"}, + }; + } + + @DataProvider(name="parseNumber") + Object[][] provider_number() { + return new Object[][] { + {DAY_OF_MONTH, TextStyle.FULL, 1, "1"}, + {DAY_OF_MONTH, TextStyle.FULL, 2, "2"}, + {DAY_OF_MONTH, TextStyle.FULL, 30, "30"}, + {DAY_OF_MONTH, TextStyle.FULL, 31, "31"}, + + {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"}, + {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"}, + {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"}, + {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"}, + }; + } + + @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(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(pos.getIndex(), input.length()); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="parseText") + 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); + assertEquals(pos.getErrorIndex(), 0); + } + + @Test(dataProvider="parseText") + 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(pos.getIndex(), input.length()); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="parseText") + 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); + assertEquals(pos.getErrorIndex(), 0); + } + + @Test(dataProvider="parseText") + 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(pos.getIndex(), input.length()); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + 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(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); + 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); + assertEquals(pos.getErrorIndex(), 0); + } + + //----------------------------------------------------------------------- + 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(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(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); + assertEquals(pos.getErrorIndex(), 0); + } + + //----------------------------------------------------------------------- + public void test_parse_french_short_strict_full_noMatch() throws Exception { + setStrict(true); + ParsePosition pos = new ParsePosition(0); + getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) + .parseToBuilder("janvier", pos); + assertEquals(pos.getErrorIndex(), 0); + } + + public void test_parse_french_short_strict_short_match() throws Exception { + setStrict(true); + ParsePosition pos = new ParsePosition(0); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) + .parseToBuilder("janv.", pos) + .getLong(MONTH_OF_YEAR), + 1L); + assertEquals(pos.getIndex(), 5); + } + + //----------------------------------------------------------------------- + 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(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(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(pos.getIndex(), 1); + } + + //----------------------------------------------------------------------- + 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(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(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(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 new file mode 100644 index 00000000000..cc93f461a78 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java @@ -0,0 +1,195 @@ +/* + * 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 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 org.testng.Assert.assertEquals; + +import java.util.Locale; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.temporal.TemporalField; +import test.java.time.temporal.MockFieldValue; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test TextPrinterParser. + */ +@Test(groups={"implementation"}) +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); + } + + public void test_print_append() throws Exception { + buf.append("EXISTING"); + getFormatter(DAY_OF_WEEK, TextStyle.FULL).printTo(LocalDate.of(2012, 4, 18), buf); + assertEquals(buf.toString(), "EXISTINGWednesday"); + } + + //----------------------------------------------------------------------- + @DataProvider(name="print") + Object[][] provider_dow() { + return new Object[][] { + {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"}, + {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"}, + {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"}, + {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"}, + {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"}, + {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"}, + + {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"}, + {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"}, + {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"}, + {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"}, + {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"}, + {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"}, + {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"}, + + {DAY_OF_WEEK, TextStyle.NARROW, 1, "M"}, + {DAY_OF_WEEK, TextStyle.NARROW, 2, "T"}, + {DAY_OF_WEEK, TextStyle.NARROW, 3, "W"}, + {DAY_OF_WEEK, TextStyle.NARROW, 4, "T"}, + {DAY_OF_WEEK, TextStyle.NARROW, 5, "F"}, + {DAY_OF_WEEK, TextStyle.NARROW, 6, "S"}, + {DAY_OF_WEEK, TextStyle.NARROW, 7, "S"}, + + {DAY_OF_MONTH, TextStyle.FULL, 1, "1"}, + {DAY_OF_MONTH, TextStyle.FULL, 2, "2"}, + {DAY_OF_MONTH, TextStyle.FULL, 3, "3"}, + {DAY_OF_MONTH, TextStyle.FULL, 28, "28"}, + {DAY_OF_MONTH, TextStyle.FULL, 29, "29"}, + {DAY_OF_MONTH, TextStyle.FULL, 30, "30"}, + {DAY_OF_MONTH, TextStyle.FULL, 31, "31"}, + + {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"}, + {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"}, + {DAY_OF_MONTH, TextStyle.SHORT, 3, "3"}, + {DAY_OF_MONTH, TextStyle.SHORT, 28, "28"}, + {DAY_OF_MONTH, TextStyle.SHORT, 29, "29"}, + {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"}, + {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"}, + + {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"}, + {MONTH_OF_YEAR, TextStyle.FULL, 2, "February"}, + {MONTH_OF_YEAR, TextStyle.FULL, 3, "March"}, + {MONTH_OF_YEAR, TextStyle.FULL, 4, "April"}, + {MONTH_OF_YEAR, TextStyle.FULL, 5, "May"}, + {MONTH_OF_YEAR, TextStyle.FULL, 6, "June"}, + {MONTH_OF_YEAR, TextStyle.FULL, 7, "July"}, + {MONTH_OF_YEAR, TextStyle.FULL, 8, "August"}, + {MONTH_OF_YEAR, TextStyle.FULL, 9, "September"}, + {MONTH_OF_YEAR, TextStyle.FULL, 10, "October"}, + {MONTH_OF_YEAR, TextStyle.FULL, 11, "November"}, + {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"}, + + {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 2, "Feb"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 3, "Mar"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 4, "Apr"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 5, "May"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 6, "Jun"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 7, "Jul"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 8, "Aug"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 9, "Sep"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 10, "Oct"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 11, "Nov"}, + {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"}, + }; + } + + @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); + 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); + 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); + assertEquals(buf.toString(), "janv."); + } + + //----------------------------------------------------------------------- + public void test_toString1() throws Exception { + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).toString(), "Text(MonthOfYear)"); + } + + public void test_toString2() throws Exception { + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).toString(), "Text(MonthOfYear,SHORT)"); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java b/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java new file mode 100644 index 00000000000..99ee93bb52e --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java @@ -0,0 +1,245 @@ +/* + * 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 new file mode 100644 index 00000000000..300411cb2eb --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java @@ -0,0 +1,444 @@ +/* + * 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 static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.text.ParsePosition; +import java.time.ZoneOffset; +import java.time.format.DateTimeBuilder; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test ZoneOffsetPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestZoneOffsetParser extends AbstractTestPrinterParser { + + //----------------------------------------------------------------------- + @DataProvider(name="error") + Object[][] data_error() { + return new Object[][] { + {"+HH:MM:ss", "Z", "hello", -1, IndexOutOfBoundsException.class}, + {"+HH:MM:ss", "Z", "hello", 6, IndexOutOfBoundsException.class}, + }; + } + + @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)); + } catch (RuntimeException ex) { + assertTrue(expected.isInstance(ex)); + } + } + + //----------------------------------------------------------------------- + public void test_parse_exactMatch_UTC() throws Exception { + ParsePosition pos = new ParsePosition(0); + DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos); + assertEquals(pos.getIndex(), 1); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 1); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 6); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 6); + assertParsed(dtb, ZoneOffset.UTC); + } + + //----------------------------------------------------------------------- + public void test_parse_exactMatch_UTC_EmptyUTC() throws Exception { + ParsePosition pos = new ParsePosition(0); + DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("", pos); + assertEquals(pos.getIndex(), 0); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 0); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 5); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 5); + assertParsed(dtb, ZoneOffset.UTC); + } + + //----------------------------------------------------------------------- + @DataProvider(name="offsets") + Object[][] provider_offsets() { + return new Object[][] { + {"+HH", "+00", ZoneOffset.UTC}, + {"+HH", "-00", ZoneOffset.UTC}, + {"+HH", "+01", ZoneOffset.ofHours(1)}, + {"+HH", "-01", ZoneOffset.ofHours(-1)}, + + {"+HHMM", "+0000", ZoneOffset.UTC}, + {"+HHMM", "-0000", ZoneOffset.UTC}, + {"+HHMM", "+0102", ZoneOffset.ofHoursMinutes(1, 2)}, + {"+HHMM", "-0102", ZoneOffset.ofHoursMinutes(-1, -2)}, + + {"+HH:MM", "+00:00", ZoneOffset.UTC}, + {"+HH:MM", "-00:00", ZoneOffset.UTC}, + {"+HH:MM", "+01:02", ZoneOffset.ofHoursMinutes(1, 2)}, + {"+HH:MM", "-01:02", ZoneOffset.ofHoursMinutes(-1, -2)}, + + {"+HHMMss", "+0000", ZoneOffset.UTC}, + {"+HHMMss", "-0000", ZoneOffset.UTC}, + {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HHMMss", "+0159", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)}, + {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HHMMss", "+010215", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)}, + {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HHMMss", "+000000", ZoneOffset.UTC}, + {"+HHMMss", "-000000", ZoneOffset.UTC}, + {"+HHMMss", "+010000", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HHMMss", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HHMMss", "+015959", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)}, + {"+HHMMss", "+020000", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HHMMss", "+180000", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HHMMss", "-010000", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HHMMss", "-020000", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HHMMss", "-180000", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HH:MM:ss", "+00:00", ZoneOffset.UTC}, + {"+HH:MM:ss", "-00:00", ZoneOffset.UTC}, + {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HH:MM:ss", "+01:02", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)}, + {"+HH:MM:ss", "+01:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)}, + {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HH:MM:ss", "+01:02:15", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)}, + {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HH:MM:ss", "+00:00:00", ZoneOffset.UTC}, + {"+HH:MM:ss", "-00:00:00", ZoneOffset.UTC}, + {"+HH:MM:ss", "+01:00:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HH:MM:ss", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HH:MM:ss", "+01:59:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)}, + {"+HH:MM:ss", "+02:00:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HH:MM:ss", "+18:00:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HH:MM:ss", "-01:00:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HH:MM:ss", "-02:00:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HH:MM:ss", "-18:00:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HHMMSS", "+000000", ZoneOffset.UTC}, + {"+HHMMSS", "-000000", ZoneOffset.UTC}, + {"+HHMMSS", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HHMMSS", "-010203", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)}, + + {"+HH:MM:SS", "+00:00:00", ZoneOffset.UTC}, + {"+HH:MM:SS", "-00:00:00", ZoneOffset.UTC}, + {"+HH:MM:SS", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HH:MM:SS", "-01:02:03", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)}, + }; + } + + @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); + assertEquals(pos.getIndex(), parse.length()); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length()); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length() + 5); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length() + 5); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length()); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length()); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length() + 5); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), parse.length() + 5); + assertParsed(dtb, expected); + } + + //----------------------------------------------------------------------- + @DataProvider(name="bigOffsets") + Object[][] provider_bigOffsets() { + return new Object[][] { + {"+HH", "+59", 59 * 3600}, + {"+HH", "-19", -(19 * 3600)}, + + {"+HHMM", "+1801", 18 * 3600 + 1 * 60}, + {"+HHMM", "-1801", -(18 * 3600 + 1 * 60)}, + + {"+HH:MM", "+18:01", 18 * 3600 + 1 * 60}, + {"+HH:MM", "-18:01", -(18 * 3600 + 1 * 60)}, + + {"+HHMMss", "+180103", 18 * 3600 + 1 * 60 + 3}, + {"+HHMMss", "-180103", -(18 * 3600 + 1 * 60 + 3)}, + + {"+HH:MM:ss", "+18:01:03", 18 * 3600 + 1 * 60 + 3}, + {"+HH:MM:ss", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)}, + + {"+HHMMSS", "+180103", 18 * 3600 + 1 * 60 + 3}, + {"+HHMMSS", "-180103", -(18 * 3600 + 1 * 60 + 3)}, + + {"+HH:MM:SS", "+18:01:03", 18 * 3600 + 1 * 60 + 3}, + {"+HH:MM:SS", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)}, + }; + } + + @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); + assertEquals(pos.getIndex(), parse.length()); + assertEquals(dtb.getLong(OFFSET_SECONDS), offsetSecs); + } + + //----------------------------------------------------------------------- + @DataProvider(name="badOffsets") + Object[][] provider_badOffsets() { + return new Object[][] { + {"+HH", "+1", 0}, + {"+HH", "-1", 0}, + {"+HH", "01", 0}, + {"+HH", "01", 0}, + {"+HH", "+AA", 0}, + + {"+HHMM", "+1", 0}, + {"+HHMM", "+01", 0}, + {"+HHMM", "+001", 0}, + {"+HHMM", "0102", 0}, + {"+HHMM", "+01:02", 0}, + {"+HHMM", "+AAAA", 0}, + + {"+HH:MM", "+1", 0}, + {"+HH:MM", "+01", 0}, + {"+HH:MM", "+0:01", 0}, + {"+HH:MM", "+00:1", 0}, + {"+HH:MM", "+0:1", 0}, + {"+HH:MM", "+:", 0}, + {"+HH:MM", "01:02", 0}, + {"+HH:MM", "+0102", 0}, + {"+HH:MM", "+AA:AA", 0}, + + {"+HHMMss", "+1", 0}, + {"+HHMMss", "+01", 0}, + {"+HHMMss", "+001", 0}, + {"+HHMMss", "0102", 0}, + {"+HHMMss", "+01:02", 0}, + {"+HHMMss", "+AAAA", 0}, + + {"+HH:MM:ss", "+1", 0}, + {"+HH:MM:ss", "+01", 0}, + {"+HH:MM:ss", "+0:01", 0}, + {"+HH:MM:ss", "+00:1", 0}, + {"+HH:MM:ss", "+0:1", 0}, + {"+HH:MM:ss", "+:", 0}, + {"+HH:MM:ss", "01:02", 0}, + {"+HH:MM:ss", "+0102", 0}, + {"+HH:MM:ss", "+AA:AA", 0}, + + {"+HHMMSS", "+1", 0}, + {"+HHMMSS", "+01", 0}, + {"+HHMMSS", "+001", 0}, + {"+HHMMSS", "0102", 0}, + {"+HHMMSS", "+01:02", 0}, + {"+HHMMSS", "+AAAA", 0}, + + {"+HH:MM:SS", "+1", 0}, + {"+HH:MM:SS", "+01", 0}, + {"+HH:MM:SS", "+0:01", 0}, + {"+HH:MM:SS", "+00:1", 0}, + {"+HH:MM:SS", "+0:1", 0}, + {"+HH:MM:SS", "+:", 0}, + {"+HH:MM:SS", "01:02", 0}, + {"+HH:MM:SS", "+0102", 0}, + {"+HH:MM:SS", "+AA:AA", 0}, + }; + } + + @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); + assertEquals(pos.getErrorIndex(), expectedPosition); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + 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); + assertEquals(pos.getIndex(), 1); + assertParsed(dtb, 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); + assertEquals(pos.getErrorIndex(), 0); + assertEquals(dtb, 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); + assertEquals(pos.getIndex(), 1); + assertParsed(dtb, 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); + assertEquals(pos.getIndex(), 1); + assertParsed(dtb, ZoneOffset.UTC); + } + + private void assertParsed(DateTimeBuilder dtb, ZoneOffset expectedOffset) { + if (expectedOffset == null) { + assertEquals(dtb, null); + } else { + assertEquals(dtb.getFieldValueMap().size(), 1); + assertEquals(dtb.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 new file mode 100644 index 00000000000..e4250900b05 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java @@ -0,0 +1,175 @@ +/* + * 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 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; + +/** + * Test ZoneOffsetPrinterParser. + */ +@Test(groups={"implementation"}) +public class TestZoneOffsetPrinter extends AbstractTestPrinterParser { + + private static final ZoneOffset OFFSET_0130 = ZoneOffset.of("+01:30"); + + //----------------------------------------------------------------------- + @DataProvider(name="offsets") + Object[][] provider_offsets() { + return new Object[][] { + {"+HH", "NO-OFFSET", ZoneOffset.UTC}, + {"+HH", "+01", ZoneOffset.ofHours(1)}, + {"+HH", "-01", ZoneOffset.ofHours(-1)}, + + {"+HHMM", "NO-OFFSET", ZoneOffset.UTC}, + {"+HHMM", "+0102", ZoneOffset.ofHoursMinutes(1, 2)}, + {"+HHMM", "-0102", ZoneOffset.ofHoursMinutes(-1, -2)}, + + {"+HH:MM", "NO-OFFSET", ZoneOffset.UTC}, + {"+HH:MM", "+01:02", ZoneOffset.ofHoursMinutes(1, 2)}, + {"+HH:MM", "-01:02", ZoneOffset.ofHoursMinutes(-1, -2)}, + + {"+HHMMss", "NO-OFFSET", ZoneOffset.UTC}, + {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HHMMss", "+0102", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)}, + {"+HHMMss", "+0159", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)}, + {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HHMMss", "+010215", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)}, + {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HHMMss", "NO-OFFSET", ZoneOffset.UTC}, + {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HHMMss", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HHMMss", "+015959", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)}, + {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HH:MM:ss", "NO-OFFSET", ZoneOffset.UTC}, + {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HH:MM:ss", "+01:02", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)}, + {"+HH:MM:ss", "+01:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)}, + {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HH:MM:ss", "+01:02:15", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)}, + {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HH:MM:ss", "NO-OFFSET", ZoneOffset.UTC}, + {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)}, + {"+HH:MM:ss", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HH:MM:ss", "+01:59:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)}, + {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)}, + {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)}, + {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)}, + {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)}, + {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)}, + + {"+HHMMSS", "NO-OFFSET", ZoneOffset.UTC}, + {"+HHMMSS", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HHMMSS", "-010203", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)}, + {"+HHMMSS", "+010200", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)}, + {"+HHMMSS", "-010200", ZoneOffset.ofHoursMinutesSeconds(-1, -2, 0)}, + + {"+HH:MM:SS", "NO-OFFSET", ZoneOffset.UTC}, + {"+HH:MM:SS", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)}, + {"+HH:MM:SS", "-01:02:03", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)}, + {"+HH:MM:SS", "+01:02:00", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)}, + {"+HH:MM:SS", "-01:02:00", ZoneOffset.ofHoursMinutesSeconds(-1, -2, 0)}, + }; + } + + @Test(dataProvider="offsets") + public void test_print(String pattern, String expected, ZoneOffset offset) throws Exception { + buf.append("EXISTING"); + getFormatter(pattern, "NO-OFFSET").printTo(new DateTimeBuilder(OFFSET_SECONDS, offset.getTotalSeconds()), 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 + ")"); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeException.class) + public void test_print_emptyCalendrical() throws Exception { + getFormatter("+HH:MM:ss", "Z").printTo(EMPTY_DTA, buf); + } + + public void test_print_emptyAppendable() throws Exception { + getFormatter("+HH:MM:ss", "Z").printTo(new DateTimeBuilder(OFFSET_SECONDS, OFFSET_0130.getTotalSeconds()), 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 new file mode 100644 index 00000000000..0f58634b655 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package test.java.time.format; + +import java.util.Date; +import java.util.Locale; +import java.util.Random; +import java.util.Set; +import java.util.TimeZone; + +import java.time.ZonedDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoField; +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.Test; +import static org.testng.Assert.assertEquals; + +/** + * Test ZoneTextPrinterParser + */ +@Test(groups={"implementation"}) +public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { + + protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) { + return new DateTimeFormatterBuilder().appendZoneText(style) + .toFormatter(locale) + .withSymbols(DateTimeFormatSymbols.of(locale)); + } + + public void test_printText() { + Random r = new Random(); + int N = 50; + Locale[] locales = Locale.getAvailableLocales(); + Set zids = ZoneRulesProvider.getAvailableZoneIds(); + ZonedDateTime zdt = ZonedDateTime.now(); + + //System.out.printf("locale==%d, timezone=%d%n", locales.length, zids.size()); + while (N-- > 0) { + zdt = zdt.withDayOfYear(r.nextInt(365) + 1) + .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400)); + for (String zid : zids) { + zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); + TimeZone tz = TimeZone.getTimeZone(zid); + boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); + for (Locale locale : locales) { + printText(locale, zdt, TextStyle.FULL, + tz.getDisplayName(isDST, TimeZone.LONG, locale)); + printText(locale, zdt, TextStyle.SHORT, + tz.getDisplayName(isDST, TimeZone.SHORT, locale)); + } + } + } + } + + private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, String expected) { + String result = getFormatter(locale, style).print(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? + return; + } + System.out.println("----------------"); + System.out.printf("tdz[%s]%n", zdt.toString()); + System.out.printf("[%-4s, %5s] :[%s]%n", locale.toString(), style.toString(),result); + System.out.printf("%4s, %5s :[%s]%n", "", "", expected); + } + assertEquals(result, expected); + } +} diff --git a/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java new file mode 100644 index 00000000000..255735db006 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java @@ -0,0 +1,124 @@ +/* + * 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.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; + +/** + * Mock TemporalField that returns null. + */ +public enum MockFieldNoValue implements TemporalField { + + INSTANCE; + + @Override + public String getName() { + return null; + } + + @Override + public TemporalUnit getBaseUnit() { + return WEEKS; + } + + @Override + public TemporalUnit getRangeUnit() { + return MONTHS; + } + + @Override + public ValueRange range() { + return ValueRange.of(1, 20); + } + + //----------------------------------------------------------------------- + @Override + public boolean doIsSupported(TemporalAccessor temporal) { + return true; + } + + @Override + public ValueRange doRange(TemporalAccessor temporal) { + return ValueRange.of(1, 20); + } + + @Override + public long doGet(TemporalAccessor temporal) { + throw new DateTimeException("Mock"); + } + + @Override + public R doWith(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 new file mode 100644 index 00000000000..7f478a9a539 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java @@ -0,0 +1,104 @@ +/* + * 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 test.java.time.temporal; + +import java.time.temporal.*; + +import java.time.DateTimeException; +import java.time.temporal.TemporalAccessor; + +/** + * Mock simple date-time with one field-value. + */ +public final class MockFieldValue implements TemporalAccessor { + + private final TemporalField field; + private final long value; + + public MockFieldValue(TemporalField field, long value) { + this.field = field; + this.value = value; + } + + @Override + public boolean isSupported(TemporalField field) { + return field != null && field.equals(this.field); + } + + @Override + public ValueRange range(TemporalField field) { + if (field instanceof ChronoField) { + if (isSupported(field)) { + return field.range(); + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.doRange(this); + } + + @Override + public long getLong(TemporalField field) { + if (this.field.equals(field)) { + return value; + } + throw new DateTimeException("Unsupported field: " + field); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java b/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java new file mode 100644 index 00000000000..b282cda2f85 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java @@ -0,0 +1,318 @@ +/* + * 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) 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.temporal; + +import static java.time.Month.AUGUST; +import static java.time.Month.FEBRUARY; +import static java.time.Month.JULY; +import static java.time.Month.JUNE; +import static java.time.Month.MARCH; +import static java.time.Month.OCTOBER; +import static java.time.Month.SEPTEMBER; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.testng.Assert.assertEquals; + +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneOffset; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestChronoUnit { + + //----------------------------------------------------------------------- + @DataProvider(name = "yearsBetween") + Object[][] data_yearsBetween() { + return new Object[][] { + {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 1), 0}, + {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 2), 0}, + {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 3), 0}, + + {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 1), 0}, + {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 2), 1}, + {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 3), 1}, + + {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 1), -1}, + {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 2), -1}, + {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 3), 0}, + + {date(1939, SEPTEMBER, 2), date(1945, SEPTEMBER, 3), 6}, + {date(1939, SEPTEMBER, 2), date(1945, OCTOBER, 3), 6}, + {date(1939, SEPTEMBER, 2), date(1945, AUGUST, 3), 5}, + }; + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + //----------------------------------------------------------------------- + @DataProvider(name = "monthsBetween") + Object[][] data_monthsBetween() { + return new Object[][] { + {date(2012, JULY, 2), date(2012, JULY, 1), 0}, + {date(2012, JULY, 2), date(2012, JULY, 2), 0}, + {date(2012, JULY, 2), date(2012, JULY, 3), 0}, + + {date(2012, JULY, 2), date(2012, AUGUST, 1), 0}, + {date(2012, JULY, 2), date(2012, AUGUST, 2), 1}, + {date(2012, JULY, 2), date(2012, AUGUST, 3), 1}, + + {date(2012, JULY, 2), date(2012, SEPTEMBER, 1), 1}, + {date(2012, JULY, 2), date(2012, SEPTEMBER, 2), 2}, + {date(2012, JULY, 2), date(2012, SEPTEMBER, 3), 2}, + + {date(2012, JULY, 2), date(2012, JUNE, 1), -1}, + {date(2012, JULY, 2), date(2012, JUNE, 2), -1}, + {date(2012, JULY, 2), date(2012, JUNE, 3), 0}, + + {date(2012, FEBRUARY, 27), date(2012, MARCH, 26), 0}, + {date(2012, FEBRUARY, 27), date(2012, MARCH, 27), 1}, + {date(2012, FEBRUARY, 27), date(2012, MARCH, 28), 1}, + + {date(2012, FEBRUARY, 28), date(2012, MARCH, 27), 0}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 28), 1}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 29), 1}, + + {date(2012, FEBRUARY, 29), date(2012, MARCH, 28), 0}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 29), 1}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 30), 1}, + }; + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + //----------------------------------------------------------------------- + @DataProvider(name = "weeksBetween") + Object[][] data_weeksBetween() { + return new Object[][] { + {date(2012, JULY, 2), date(2012, JUNE, 25), -1}, + {date(2012, JULY, 2), date(2012, JUNE, 26), 0}, + {date(2012, JULY, 2), date(2012, JULY, 2), 0}, + {date(2012, JULY, 2), date(2012, JULY, 8), 0}, + {date(2012, JULY, 2), date(2012, JULY, 9), 1}, + + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 21), -1}, + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 22), 0}, + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 28), 0}, + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 29), 0}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 1), 0}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 5), 0}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 6), 1}, + + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 22), -1}, + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 23), 0}, + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 28), 0}, + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 29), 0}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 1), 0}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 6), 0}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 7), 1}, + }; + } + + @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); + } + + @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); + } + + //----------------------------------------------------------------------- + @DataProvider(name = "daysBetween") + Object[][] data_daysBetween() { + return new Object[][] { + {date(2012, JULY, 2), date(2012, JULY, 1), -1}, + {date(2012, JULY, 2), date(2012, JULY, 2), 0}, + {date(2012, JULY, 2), date(2012, JULY, 3), 1}, + + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 27), -1}, + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 28), 0}, + {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 29), 1}, + {date(2012, FEBRUARY, 28), date(2012, MARCH, 1), 2}, + + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 27), -2}, + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 28), -1}, + {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 29), 0}, + {date(2012, FEBRUARY, 29), date(2012, MARCH, 1), 1}, + + {date(2012, MARCH, 1), date(2012, FEBRUARY, 27), -3}, + {date(2012, MARCH, 1), date(2012, FEBRUARY, 28), -2}, + {date(2012, MARCH, 1), date(2012, FEBRUARY, 29), -1}, + {date(2012, MARCH, 1), date(2012, MARCH, 1), 0}, + {date(2012, MARCH, 1), date(2012, MARCH, 2), 1}, + + {date(2012, MARCH, 1), date(2013, FEBRUARY, 28), 364}, + {date(2012, MARCH, 1), date(2013, MARCH, 1), 365}, + + {date(2011, MARCH, 1), date(2012, FEBRUARY, 28), 364}, + {date(2011, MARCH, 1), date(2012, FEBRUARY, 29), 365}, + {date(2011, MARCH, 1), date(2012, MARCH, 1), 366}, + }; + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + @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); + } + + //----------------------------------------------------------------------- + private static LocalDate date(int year, Month month, int dom) { + return LocalDate.of(year, month, dom); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java b/jdk/test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java new file mode 100644 index 00000000000..bdade55f572 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java @@ -0,0 +1,112 @@ +/* + * 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) 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 test.java.time.temporal; + +import java.time.temporal.*; + +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.Collections; + +import org.testng.annotations.Test; + +/** + * Test Adjusters. + */ +@Test(groups={"implementation"}) +public class TestDateTimeAdjusters { + + @SuppressWarnings("rawtypes") + public void test_constructor() throws Exception { + for (Constructor constructor : Adjusters.class.getDeclaredConstructors()) { + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + constructor.setAccessible(true); + constructor.newInstance(Collections.nCopies(constructor.getParameterTypes().length, null).toArray()); + } + } + + public void factory_firstDayOfMonthSame() { + assertSame(Adjusters.firstDayOfMonth(), Adjusters.firstDayOfMonth()); + } + + public void factory_lastDayOfMonthSame() { + assertSame(Adjusters.lastDayOfMonth(), Adjusters.lastDayOfMonth()); + } + + public void factory_firstDayOfNextMonthSame() { + assertSame(Adjusters.firstDayOfNextMonth(), Adjusters.firstDayOfNextMonth()); + } + + public void factory_firstDayOfYearSame() { + assertSame(Adjusters.firstDayOfYear(), Adjusters.firstDayOfYear()); + } + + public void factory_lastDayOfYearSame() { + assertSame(Adjusters.lastDayOfYear(), Adjusters.lastDayOfYear()); + } + + public void factory_firstDayOfNextYearSame() { + assertSame(Adjusters.firstDayOfNextYear(), Adjusters.firstDayOfNextYear()); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java b/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java new file mode 100644 index 00000000000..328ead5e4e2 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java @@ -0,0 +1,171 @@ +/* + * 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.temporal; + +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.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static org.testng.Assert.assertEquals; + +import java.time.LocalDate; +import java.time.format.DateTimeBuilder; +import java.time.temporal.TemporalField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +public class TestDateTimeBuilderCombinations { + + @DataProvider(name = "combine") + Object[][] data_combine() { + return new Object[][] { + {YEAR, 2012, MONTH_OF_YEAR, 6, DAY_OF_MONTH, 3, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)}, + {EPOCH_MONTH, (2012 - 1970) * 12 + 6 - 1, DAY_OF_MONTH, 3, null, null, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)}, + {YEAR, 2012, ALIGNED_WEEK_OF_YEAR, 6, DAY_OF_WEEK, 3, null, null, LocalDate.class, LocalDate.of(2012, 2, 8)}, + {YEAR, 2012, DAY_OF_YEAR, 155, null, null, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)}, +// {ERA, 1, YEAR_OF_ERA, 2012, DAY_OF_YEAR, 155, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)}, + {YEAR, 2012, MONTH_OF_YEAR, 6, null, null, null, null, LocalDate.class, null}, + {EPOCH_DAY, 12, null, null, null, null, null, null, LocalDate.class, LocalDate.of(1970, 1, 13)}, + }; + } + + @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()); + if (field2 != null) { + builder.addFieldValue(field2, value2.longValue()); + } + if (field3 != null) { + builder.addFieldValue(field3, value3.longValue()); + } + if (field4 != null) { + builder.addFieldValue(field4, value4.longValue()); + } + 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}, + }; + } + + @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(); + if (expectedVal != null) { + assertEquals(builder.getLong(query), expectedVal.longValue()); + } else { + assertEquals(builder.containsFieldValue(query), 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/TestDateTimeValueRange.java b/jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java new file mode 100644 index 00000000000..d7397d41e64 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java @@ -0,0 +1,274 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import java.time.temporal.ValueRange; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test. + */ +@Test +public class TestDateTimeValueRange extends AbstractTest { + + //----------------------------------------------------------------------- + // Basics + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(ValueRange.class); + } + + //----------------------------------------------------------------------- + // Serialization + //----------------------------------------------------------------------- + public void test_serialization() throws Exception { + Object obj = ValueRange.of(1, 2, 3, 4); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(ois.readObject(), obj); + } + + //----------------------------------------------------------------------- + // of(long,long) + //----------------------------------------------------------------------- + public void test_of_longlong() { + ValueRange test = ValueRange.of(1, 12); + assertEquals(test.getMinimum(), 1); + assertEquals(test.getLargestMinimum(), 1); + assertEquals(test.getSmallestMaximum(), 12); + assertEquals(test.getMaximum(), 12); + assertEquals(test.isFixed(), true); + assertEquals(test.isIntValue(), true); + } + + public void test_of_longlong_big() { + ValueRange test = ValueRange.of(1, 123456789012345L); + assertEquals(test.getMinimum(), 1); + assertEquals(test.getLargestMinimum(), 1); + assertEquals(test.getSmallestMaximum(), 123456789012345L); + assertEquals(test.getMaximum(), 123456789012345L); + assertEquals(test.isFixed(), true); + assertEquals(test.isIntValue(), false); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_of_longlong_minGtMax() { + ValueRange.of(12, 1); + } + + //----------------------------------------------------------------------- + // of(long,long,long) + //----------------------------------------------------------------------- + public void test_of_longlonglong() { + ValueRange test = ValueRange.of(1, 28, 31); + assertEquals(test.getMinimum(), 1); + assertEquals(test.getLargestMinimum(), 1); + assertEquals(test.getSmallestMaximum(), 28); + assertEquals(test.getMaximum(), 31); + assertEquals(test.isFixed(), false); + assertEquals(test.isIntValue(), true); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_of_longlonglong_minGtMax() { + ValueRange.of(12, 1, 2); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_of_longlonglong_smallestmaxminGtMax() { + ValueRange.of(1, 31, 28); + } + + //----------------------------------------------------------------------- + // of(long,long,long,long) + //----------------------------------------------------------------------- + @DataProvider(name="valid") + Object[][] data_valid() { + return new Object[][] { + {1, 1, 1, 1}, + {1, 1, 1, 2}, + {1, 1, 2, 2}, + {1, 2, 3, 4}, + {1, 1, 28, 31}, + {1, 3, 31, 31}, + {-5, -4, -3, -2}, + {-5, -4, 3, 4}, + {1, 20, 10, 31}, + }; + } + + @Test(dataProvider="valid") + public void test_of_longlonglonglong(long sMin, long lMin, long sMax, long lMax) { + ValueRange test = ValueRange.of(sMin, lMin, sMax, lMax); + assertEquals(test.getMinimum(), sMin); + assertEquals(test.getLargestMinimum(), lMin); + assertEquals(test.getSmallestMaximum(), sMax); + assertEquals(test.getMaximum(), lMax); + assertEquals(test.isFixed(), sMin == lMin && sMax == lMax); + assertEquals(test.isIntValue(), true); + } + + @DataProvider(name="invalid") + Object[][] data_invalid() { + return new Object[][] { + {1, 2, 31, 28}, + {1, 31, 2, 28}, + {31, 2, 1, 28}, + {31, 2, 3, 28}, + + {2, 1, 28, 31}, + {2, 1, 31, 28}, + {12, 13, 1, 2}, + }; + } + + @Test(dataProvider="invalid", expectedExceptions=IllegalArgumentException.class) + public void test_of_longlonglonglong_invalid(long sMin, long lMin, long sMax, long lMax) { + ValueRange.of(sMin, lMin, sMax, lMax); + } + + //----------------------------------------------------------------------- + // isValidValue(long) + //----------------------------------------------------------------------- + public void test_isValidValue_long() { + ValueRange test = ValueRange.of(1, 28, 31); + assertEquals(test.isValidValue(0), false); + assertEquals(test.isValidValue(1), true); + assertEquals(test.isValidValue(2), true); + assertEquals(test.isValidValue(30), true); + assertEquals(test.isValidValue(31), true); + assertEquals(test.isValidValue(32), false); + } + + //----------------------------------------------------------------------- + // isValidIntValue(long) + //----------------------------------------------------------------------- + public void test_isValidValue_long_int() { + ValueRange test = ValueRange.of(1, 28, 31); + assertEquals(test.isValidValue(0), false); + assertEquals(test.isValidValue(1), true); + assertEquals(test.isValidValue(31), true); + assertEquals(test.isValidValue(32), false); + } + + public void test_isValidValue_long_long() { + ValueRange test = ValueRange.of(1, 28, Integer.MAX_VALUE + 1L); + assertEquals(test.isValidIntValue(0), false); + assertEquals(test.isValidIntValue(1), false); + assertEquals(test.isValidIntValue(31), false); + assertEquals(test.isValidIntValue(32), false); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + public void test_equals1() { + ValueRange a = ValueRange.of(1, 2, 3, 4); + ValueRange b = ValueRange.of(1, 2, 3, 4); + assertEquals(a.equals(a), true); + assertEquals(a.equals(b), true); + assertEquals(b.equals(a), true); + assertEquals(b.equals(b), true); + assertEquals(a.hashCode() == b.hashCode(), true); + } + + public void test_equals2() { + ValueRange a = ValueRange.of(1, 2, 3, 4); + assertEquals(a.equals(ValueRange.of(0, 2, 3, 4)), false); + assertEquals(a.equals(ValueRange.of(1, 3, 3, 4)), false); + assertEquals(a.equals(ValueRange.of(1, 2, 4, 4)), false); + assertEquals(a.equals(ValueRange.of(1, 2, 3, 5)), false); + } + + public void test_equals_otherType() { + ValueRange a = ValueRange.of(1, 12); + assertEquals(a.equals("Rubbish"), false); + } + + public void test_equals_null() { + ValueRange a = ValueRange.of(1, 12); + assertEquals(a.equals(null), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + public void test_toString() { + assertEquals(ValueRange.of(1, 1, 4, 4).toString(), "1 - 4"); + assertEquals(ValueRange.of(1, 1, 3, 4).toString(), "1 - 3/4"); + assertEquals(ValueRange.of(1, 2, 3, 4).toString(), "1/2 - 3/4"); + assertEquals(ValueRange.of(1, 2, 4, 4).toString(), "1/2 - 4"); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java b/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java new file mode 100644 index 00000000000..9fc01553202 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java @@ -0,0 +1,181 @@ +/* + * 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.temporal; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +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 java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import java.time.DayOfWeek; +import java.time.LocalDate; +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; + +/** + * Test. + */ +@Test +public class TestISOChronoImpl { + + @DataProvider(name = "RangeVersusCalendar") + Object[][] provider_rangeVersusCalendar() { + return new Object[][]{ + {LocalDate.of(1900, 1, 4), LocalDate.of(2100, 1, 8)}, + //{LocalDate.of(1583, 1, 1), LocalDate.of(2100, 1, 1)}, + }; + } + + //----------------------------------------------------------------------- + // Verify ISO Calendar matches java.util.Calendar for range + //----------------------------------------------------------------------- + @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar") + 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); + + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.set(Calendar.YEAR, isoDate.get(YEAR)); + cal.set(Calendar.MONTH, isoDate.get(MONTH_OF_YEAR) - 1); + cal.set(Calendar.DAY_OF_MONTH, isoDate.get(DAY_OF_MONTH)); + + while (isoDate.isBefore(isoEndDate)) { + assertEquals(isoDate.get(DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + isoDate + "; cal: " + cal); + assertEquals(isoDate.get(MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + isoDate); + assertEquals(isoDate.get(YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + isoDate); + + isoDate = isoDate.plus(1, ChronoUnit.DAYS); + cal.add(Calendar.DAY_OF_MONTH, 1); + } + } + + //----------------------------------------------------------------------- + // Verify ISO Calendar matches java.util.Calendar + // DayOfWeek, WeekOfMonth, WeekOfYear for range + //----------------------------------------------------------------------- + @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar") + public void test_DayOfWeek_ISOChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { + GregorianCalendar cal = new GregorianCalendar(); + assertEquals(cal.getCalendarType(), "gregory", "Unexpected calendar type"); + ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(isoStartDate); + + for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { + for (int minDays = 1; minDays <= 7; minDays++) { + WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); + cal.setFirstDayOfWeek(Math.floorMod(firstDayOfWeek.getValue(), 7) + 1); + cal.setMinimalDaysInFirstWeek(minDays); + + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.set(Calendar.YEAR, isoDate.get(YEAR)); + cal.set(Calendar.MONTH, isoDate.get(MONTH_OF_YEAR) - 1); + cal.set(Calendar.DAY_OF_MONTH, isoDate.get(DAY_OF_MONTH)); + + while (isoDate.isBefore(isoEndDate)) { + assertEquals(isoDate.get(DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + isoDate + "; cal: " + cal); + assertEquals(isoDate.get(MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + isoDate); + assertEquals(isoDate.get(YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + isoDate); + int jDOW = Math.floorMod(cal.get(Calendar.DAY_OF_WEEK) - 2, 7) + 1; + int isoDOW = isoDate.get(weekDef.dayOfWeek()); + if (jDOW != isoDOW) { + System.err.printf(" DOW vs Calendar jdow: %s, isoDate(DOW): %s, isoDate: %s, WeekDef: %s%n", jDOW, isoDOW, isoDate, weekDef); + } + assertEquals(jDOW, isoDOW, "Calendar DayOfWeek does not match ISO DayOfWeek"); + + int jweekOfMonth = cal.get(Calendar.WEEK_OF_MONTH); + int isoWeekOfMonth = isoDate.get(weekDef.weekOfMonth()); + if (jweekOfMonth != isoWeekOfMonth) { + System.err.printf(" WeekOfMonth jWeekOfMonth: %s, isoWeekOfMonth: %s, isoDate: %s, %s%n", + jweekOfMonth, isoWeekOfMonth, isoDate, weekDef); + } + assertEquals(jweekOfMonth, isoWeekOfMonth, "Calendar WeekOfMonth does not match ISO WeekOfMonth"); + + int jweekOfYear = cal.get(Calendar.WEEK_OF_YEAR); + int isoWeekOfYear = isoDate.get(weekDef.weekOfYear()); + if (jweekOfYear != isoWeekOfYear) { + // TBD: Issue #186 Remove misleading output pending resolution + // System.err.printf(" Mismatch WeekOfYear jweekOfYear: %s, isoWeekOfYear: %s, isoDate: %s, WeekDef: %s%n", jweekOfYear, isoWeekOfYear, isoDate, weekDef); + } + //assertEquals(jweekOfYear, isoWeekOfYear, "Calendar WeekOfYear does not match ISO WeekOfYear"); + + isoDate = isoDate.plus(1, ChronoUnit.DAYS); + cal.add(Calendar.DAY_OF_MONTH, 1); + } + } + } + } + + /** + * Return the ISO Day of Week from a java.util.Calendr DAY_OF_WEEK. + * @param the java.util.Calendar day of week (1=Sunday, 7=Saturday) + * @return the ISO DayOfWeek + */ + private DayOfWeek toISOfromCalendarDOW(int i) { + return DayOfWeek.of(Math.floorMod(i - 2, 7) + 1); + } +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java b/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java new file mode 100644 index 00000000000..cadd1a378c6 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java @@ -0,0 +1,121 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; + +import java.util.Calendar; +import java.util.Locale; +import java.util.TimeZone; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.temporal.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoLocalDate; +import java.time.temporal.ChronoUnit; +import java.time.calendar.JapaneseChrono; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestJapaneseChronoImpl { + + /** + * Range of years to check consistency with java.util.Calendar + */ + @DataProvider(name="RangeVersusCalendar") + Object[][] provider_rangeVersusCalendar() { + return new Object[][] { + {LocalDate.of(1868, 1, 1), LocalDate.of(2100, 1, 1)}, + }; + } + + //----------------------------------------------------------------------- + // Verify Japanese Calendar matches java.util.Calendar for range + //----------------------------------------------------------------------- + @Test(groups={"implementation"}, dataProvider="RangeVersusCalendar") + public void test_JapaneseChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { + Locale locale = Locale.forLanguageTag("ja-JP-u-ca-japanese"); + assertEquals(locale.toString(), "ja_JP_#u-ca-japanese", "Unexpected locale"); + + Calendar cal = java.util.Calendar.getInstance(locale); + assertEquals(cal.getCalendarType(), "japanese", "Unexpected calendar type"); + + ChronoLocalDate jDate = JapaneseChrono.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); + long millis = jodt.toInstant().toEpochMilli(); + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.setTimeInMillis(millis); + + while (jDate.isBefore(isoEndDate)) { + assertEquals(jDate.get(ChronoField.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + jDate + "; cal: " + cal); + assertEquals(jDate.get(ChronoField.MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + jDate); + assertEquals(jDate.get(ChronoField.YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + jDate); + + jDate = jDate.plus(1, ChronoUnit.DAYS); + cal.add(Calendar.DAY_OF_MONTH, 1); + } + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java b/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java new file mode 100644 index 00000000000..002d4f7e286 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java @@ -0,0 +1,148 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.time.LocalDate; +import java.time.Month; +import java.time.temporal.MonthDay; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test MonthDay. + */ +@Test +public class TestMonthDay extends AbstractTest { + + private MonthDay TEST_07_15; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_07_15 = MonthDay.of(7, 15); + } + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(MonthDay.class); + } + + //----------------------------------------------------------------------- + void check(MonthDay test, int m, int d) { + assertEquals(test.getMonth().getValue(), m); + assertEquals(test.getDayOfMonth(), d); + } + + @Test(groups={"implementation"}) + public void test_with_Month_noChangeSame() { + MonthDay test = MonthDay.of(6, 30); + assertSame(test.with(Month.JUNE), test); + } + + @Test(groups={"implementation"}) + public void test_withMonth_int_noChangeSame() { + MonthDay test = MonthDay.of(6, 30); + assertSame(test.withMonth(6), test); + } + @Test(groups={"implementation"}) + public void test_withDayOfMonth_noChangeSame() { + MonthDay test = MonthDay.of(6, 30); + assertSame(test.withDayOfMonth(30), test); + } + + @Test(groups={"implementation"}) + public void test_adjustDate_same() { + MonthDay test = MonthDay.of(6, 30); + LocalDate date = LocalDate.of(2007, 6, 30); + assertSame(test.adjustInto(date), date); + } + + void doTest_comparisons_MonthDay(MonthDay... localDates) { + for (int i = 0; i < localDates.length; i++) { + MonthDay a = localDates[i]; + for (int j = 0; j < localDates.length; j++) { + MonthDay b = localDates[j]; + if (i < j) { + assertTrue(a.compareTo(b) < 0, a + " <=> " + b); + assertEquals(a.isBefore(b), true, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else if (i > j) { + assertTrue(a.compareTo(b) > 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), true, a + " <=> " + b); + assertEquals(a.equals(b), false, a + " <=> " + b); + } else { + assertEquals(a.compareTo(b), 0, a + " <=> " + b); + assertEquals(a.isBefore(b), false, a + " <=> " + b); + assertEquals(a.isAfter(b), false, a + " <=> " + b); + assertEquals(a.equals(b), true, a + " <=> " + b); + } + } + } + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java b/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java new file mode 100644 index 00000000000..5ba00329b8f --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java @@ -0,0 +1,78 @@ +/* + * 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.temporal; + +import java.time.temporal.OffsetDate; + +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test OffsetDate. + */ +@Test +public class TestOffsetDate extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(OffsetDate.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java new file mode 100644 index 00000000000..9ee46725c8a --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java @@ -0,0 +1,325 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertSame; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.temporal.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. + */ +@Test +public class TestOffsetDateTime extends AbstractTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private OffsetDateTime TEST_2008_6_30_11_30_59_000000500; + + @BeforeMethod(groups={"tck","implementation"}) + public void setUp() { + TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE); + } + + @Test + public void test_immutable() { + assertImmutable(OffsetDateTime.class); + } + + //----------------------------------------------------------------------- + // basics + //----------------------------------------------------------------------- + @DataProvider(name="sampleTimes") + Object[][] provider_sampleTimes() { + return new Object[][] { + {2008, 6, 30, 11, 30, 20, 500, OFFSET_PONE}, + {2008, 6, 30, 11, 0, 0, 0, OFFSET_PONE}, + {2008, 6, 30, 23, 59, 59, 999999999, OFFSET_PONE}, + {-1, 1, 1, 0, 0, 0, 0, OFFSET_PONE}, + }; + } + + @Test(dataProvider="sampleTimes", groups={"implementation"}) + public void test_get_same(int y, int o, int d, int h, int m, int s, int n, ZoneOffset offset) { + LocalDate localDate = LocalDate.of(y, o, d); + LocalTime localTime = LocalTime.of(h, m, s, n); + LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); + OffsetDateTime a = OffsetDateTime.of(localDateTime, offset); + + assertSame(a.getOffset(), offset); + assertSame(a.getDate(), localDate); + assertSame(a.getTime(), localTime); + assertSame(a.getDateTime(), localDateTime); + } + + //----------------------------------------------------------------------- + // withOffsetSameLocal() + //----------------------------------------------------------------------- + @Test(groups={"implementation"}) + 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.getOffset(), OFFSET_PTWO); + } + + @Test(groups={"implementation"}) + public void test_withOffsetSameLocal_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withOffsetSameLocal(OFFSET_PONE); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withOffsetSameInstant_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withOffsetSameInstant(OFFSET_PONE); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withYear_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withYear(2008); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withMonth_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withMonth(6); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withDayOfMonth_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withDayOfMonth(30); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withDayOfYear_noChange() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.withDayOfYear(31 + 29 + 31 + 30 + 31 + 30); + assertSame(t, TEST_2008_6_30_11_30_59_000000500); + } + + @Test(groups={"implementation"}) + public void test_withHour_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withHour(11); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withMinute_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withMinute(30); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withSecond_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.withSecond(59); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_withNanoOfSecond_noChange() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE); + OffsetDateTime test = base.withNano(1); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plus_Period_zero() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2008_6_30_11_30_59_000000500); + } + + @Test(groups={"implementation"}) + public void test_plusYears_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusYears(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusMonths_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusMonths(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusWeeks_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusWeeks(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusDays_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusDays(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusHours_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusHours(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusMinutes_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusMinutes(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusSeconds_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusSeconds(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_plusNanos_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.plusNanos(0); + } + + @Test(groups={"implementation"}) + public void test_minus_Period_zero() { + OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(MockSimplePeriod.ZERO_DAYS); + assertSame(t, TEST_2008_6_30_11_30_59_000000500); + } + + @Test(groups={"implementation"}) + public void test_minusYears_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusYears(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusMonths_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusMonths(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusWeeks_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusWeeks(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusDays_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusDays(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusHours_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusHours(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusMinutes_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusMinutes(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusSeconds_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusSeconds(0); + assertSame(test, base); + } + + @Test(groups={"implementation"}) + public void test_minusNanos_zero() { + OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime test = base.minusNanos(0); + assertSame(test, base); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java new file mode 100644 index 00000000000..7922c37589f --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java @@ -0,0 +1,347 @@ +/* + * 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.temporal; + +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneOffset; + +import java.time.temporal.OffsetDateTime; +import java.time.temporal.Year; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +/** + * Test OffsetDate creation. + */ +@Test +public class TestOffsetDateTime_instants { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_MAX = ZoneOffset.ofHours(18); + private static final ZoneOffset OFFSET_MIN = ZoneOffset.ofHours(-18); + + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class) + public void factory_ofInstant_nullInstant() { + OffsetDateTime.ofInstant((Instant) null, OFFSET_PONE); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_ofInstant_nullOffset() { + Instant instant = Instant.ofEpochSecond(0L); + OffsetDateTime.ofInstant(instant, (ZoneOffset) null); + } + + public void factory_ofInstant_allSecsInDay() { + for (int i = 0; i < (24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_PONE); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonth(), Month.JANUARY); + 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); + } + } + + public void factory_ofInstant_allDaysInCycle() { + // sanity check using different algorithm + OffsetDateTime expected = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + for (long i = 0; i < 146097; i++) { + Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC); + assertEquals(test, expected); + expected = expected.plusDays(1); + } + } + + public void factory_ofInstant_history() { + doTest_factory_ofInstant_all(-2820, 2820); + } + + //----------------------------------------------------------------------- + public void factory_ofInstant_minYear() { + doTest_factory_ofInstant_all(Year.MIN_VALUE, Year.MIN_VALUE + 420); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_ofInstant_tooLow() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE - 1; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L); + OffsetDateTime.ofInstant(instant, ZoneOffset.UTC); + } + + public void factory_ofInstant_maxYear() { + doTest_factory_ofInstant_all(Year.MAX_VALUE - 420, Year.MAX_VALUE); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_ofInstant_tooBig() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + long year = Year.MAX_VALUE + 1L; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L); + OffsetDateTime.ofInstant(instant, ZoneOffset.UTC); + } + + //----------------------------------------------------------------------- + public void factory_ofInstant_minWithMinOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MIN.getTotalSeconds()); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MIN); + assertEquals(test.getYear(), Year.MIN_VALUE); + assertEquals(test.getMonth().getValue(), 1); + assertEquals(test.getDayOfMonth(), 1); + assertEquals(test.getOffset(), OFFSET_MIN); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + public void factory_ofInstant_minWithMaxOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MIN_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MAX.getTotalSeconds()); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MAX); + assertEquals(test.getYear(), Year.MIN_VALUE); + assertEquals(test.getMonth().getValue(), 1); + assertEquals(test.getDayOfMonth(), 1); + assertEquals(test.getOffset(), OFFSET_MAX); + assertEquals(test.getHour(), 0); + assertEquals(test.getMinute(), 0); + assertEquals(test.getSecond(), 0); + assertEquals(test.getNano(), 0); + } + + public void factory_ofInstant_maxWithMinOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MAX_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MIN.getTotalSeconds()); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MIN); + assertEquals(test.getYear(), Year.MAX_VALUE); + assertEquals(test.getMonth().getValue(), 12); + assertEquals(test.getDayOfMonth(), 31); + assertEquals(test.getOffset(), OFFSET_MIN); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 0); + } + + public void factory_ofInstant_maxWithMaxOffset() { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int year = Year.MAX_VALUE; + long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970; + Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MAX.getTotalSeconds()); + OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MAX); + assertEquals(test.getYear(), Year.MAX_VALUE); + assertEquals(test.getMonth().getValue(), 12); + assertEquals(test.getDayOfMonth(), 31); + assertEquals(test.getOffset(), OFFSET_MAX); + assertEquals(test.getHour(), 23); + assertEquals(test.getMinute(), 59); + assertEquals(test.getSecond(), 59); + assertEquals(test.getNano(), 0); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=DateTimeException.class) + public void factory_ofInstant_maxInstantWithMaxOffset() { + Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE); + OffsetDateTime.ofInstant(instant, OFFSET_MAX); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_ofInstant_maxInstantWithMinOffset() { + Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE); + OffsetDateTime.ofInstant(instant, OFFSET_MIN); + } + + //----------------------------------------------------------------------- + private void doTest_factory_ofInstant_all(long minYear, long maxYear) { + long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + int minOffset = (minYear <= 0 ? 0 : 3); + int maxOffset = (maxYear <= 0 ? 0 : 3); + long minDays = (minYear * 365L + ((minYear + minOffset) / 4L - (minYear + minOffset) / 100L + (minYear + minOffset) / 400L)) - days_0000_to_1970; + long maxDays = (maxYear * 365L + ((maxYear + maxOffset) / 4L - (maxYear + maxOffset) / 100L + (maxYear + maxOffset) / 400L)) + 365L - days_0000_to_1970; + + final LocalDate maxDate = LocalDate.of(Year.MAX_VALUE, 12, 31); + OffsetDateTime expected = OffsetDateTime.of(LocalDate.of((int) minYear, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + for (long i = minDays; i < maxDays; i++) { + Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L); + try { + OffsetDateTime test = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC); + assertEquals(test, expected); + if (expected.getDate().equals(maxDate) == false) { + expected = expected.plusDays(1); + } + } catch (RuntimeException|Error ex) { + System.out.println("Error: " + i + " " + expected); + throw ex; + } + } + } + + // for performance testing + // private void doTest_factory_ofInstant_all(int minYear, int maxYear) { + // long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7); + // int minOffset = (minYear <= 0 ? 0 : 3); + // int maxOffset = (maxYear <= 0 ? 0 : 3); + // long minDays = (long) (minYear * 365L + ((minYear + minOffset) / 4L - (minYear + minOffset) / 100L + (minYear + minOffset) / 400L)) - days_0000_to_1970; + // long maxDays = (long) (maxYear * 365L + ((maxYear + maxOffset) / 4L - (maxYear + maxOffset) / 100L + (maxYear + maxOffset) / 400L)) + 365L - days_0000_to_1970; + // + // OffsetDateTime expected = OffsetDateTime.dateTime(minYear, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + // Date cutover = new Date(Long.MIN_VALUE); + // GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + // cal.setGregorianChange(cutover); + // for (long i = minDays; i < maxDays; i++) { + // Instant instant = Instant.instant(i * 24L * 60L * 60L); + // try { + // cal.setTimeInMillis(instant.getEpochSecond() * 1000L); + // assertEquals(cal.get(GregorianCalendar.MONTH), expected.getMonth().getValue() - 1); + // assertEquals(cal.get(GregorianCalendar.DAY_OF_MONTH), expected.getDayOfMonth().getValue()); + // expected = expected.plusDays(1); + // } catch (RuntimeException ex) { + // System.out.println("Error: " + i + " " + expected); + // throw ex; + // } catch (Error ex) { + // System.out.println("Error: " + i + " " + expected); + // throw ex; + // } + // } + // } + + //----------------------------------------------------------------------- + public void test_toInstant_19700101() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), 0); + assertEquals(test.getNano(), 0); + } + + public void test_toInstant_19700101_oneNano() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 1), ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), 0); + assertEquals(test.getNano(), 1); + } + + public void test_toInstant_19700101_minusOneNano() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(23, 59, 59, 999999999), ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), -1); + assertEquals(test.getNano(), 999999999); + } + + public void test_toInstant_19700102() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 2), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), 24L * 60L * 60L); + assertEquals(test.getNano(), 0); + } + + public void test_toInstant_19691231() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + Instant test = dt.toInstant(); + assertEquals(test.getEpochSecond(), -24L * 60L * 60L); + assertEquals(test.getNano(), 0); + } + + //----------------------------------------------------------------------- + public void test_toEpochSecond_19700101() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), 0); + } + + public void test_toEpochSecond_19700101_oneNano() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of( 0, 0, 0, 1), ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), 0); + } + + public void test_toEpochSecond_19700101_minusOneNano() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(23, 59, 59, 999999999), ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), -1); + } + + public void test_toEpochSecond_19700102() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 2), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), 24L * 60L * 60L); + } + + public void test_toEpochSecond_19691231() { + OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + assertEquals(dt.toEpochSecond(), -24L * 60L * 60L); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java b/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java new file mode 100644 index 00000000000..d6e9eff0b3f --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java @@ -0,0 +1,78 @@ +/* + * 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.temporal; + +import java.time.temporal.OffsetTime; + +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test OffsetTime. + */ +@Test +public class TestOffsetTime extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(OffsetTime.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java b/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java new file mode 100644 index 00000000000..9fd69cfa76b --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java @@ -0,0 +1,122 @@ +/* + * 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.temporal; + +import static org.testng.Assert.assertEquals; + +import java.util.Calendar; +import java.util.Locale; +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 org.testng.annotations.Test; +import org.testng.annotations.DataProvider; + +/** + * Test. + */ +@Test +public class TestThaiBuddhistChronoImpl { + + /** + * Range of years to check consistency with java.util.Calendar + */ + @DataProvider(name="RangeVersusCalendar") + Object[][] provider_rangeVersusCalendar() { + return new Object[][] { + {LocalDate.of(1583, 1, 1), LocalDate.of(2100, 1, 1)}, + }; + } + + //----------------------------------------------------------------------- + // Verify ThaiBuddhist Calendar matches java.util.Calendar for range + //----------------------------------------------------------------------- + @Test(groups={"implementation"}, dataProvider="RangeVersusCalendar") + public void test_ThaiBuddhistChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { + Locale locale = Locale.forLanguageTag("th-TH--u-ca-buddhist"); + assertEquals(locale.toString(), "th_TH", "Unexpected locale"); + Calendar cal = java.util.Calendar.getInstance(locale); + assertEquals(cal.getCalendarType(), "buddhist", "Unexpected calendar type"); + + ChronoLocalDate thaiDate = ThaiBuddhistChrono.INSTANCE.date(isoStartDate); + + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.set(Calendar.YEAR, thaiDate.get(ChronoField.YEAR)); + cal.set(Calendar.MONTH, thaiDate.get(ChronoField.MONTH_OF_YEAR) - 1); + cal.set(Calendar.DAY_OF_MONTH, thaiDate.get(ChronoField.DAY_OF_MONTH)); + + while (thaiDate.isBefore(isoEndDate)) { + assertEquals(thaiDate.get(ChronoField.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + thaiDate + "; cal: " + cal); + assertEquals(thaiDate.get(ChronoField.MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + thaiDate); + assertEquals(thaiDate.get(ChronoField.YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + thaiDate); + + thaiDate = thaiDate.plus(1, ChronoUnit.DAYS); + cal.add(Calendar.DAY_OF_MONTH, 1); + } + } + + private String calToString(Calendar cal) { + return String.format("%04d-%02d-%02d", + cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestYear.java b/jdk/test/java/time/test/java/time/temporal/TestYear.java new file mode 100644 index 00000000000..5880ac46820 --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestYear.java @@ -0,0 +1,78 @@ +/* + * 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.temporal; + +import java.time.temporal.Year; + +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test Year. + */ +@Test +public class TestYear extends AbstractTest { + + @Test + public void test_immutable() { + assertImmutable(Year.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java b/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java new file mode 100644 index 00000000000..ab0d7f4c8cb --- /dev/null +++ b/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java @@ -0,0 +1,79 @@ +/* + * 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.temporal; + +import java.time.temporal.YearMonth; + +import org.testng.annotations.Test; +import test.java.time.AbstractTest; + +/** + * Test YearMonth. + */ +@Test +public class TestYearMonth extends AbstractTest { + + //----------------------------------------------------------------------- + @Test + public void test_immutable() { + assertImmutable(YearMonth.class); + } + +} diff --git a/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java b/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java new file mode 100644 index 00000000000..80569674bb6 --- /dev/null +++ b/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java @@ -0,0 +1,101 @@ +/* + * 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 test.java.time.zone; + +import java.time.zone.*; + +import static org.testng.Assert.assertEquals; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +import org.testng.annotations.Test; + +/** + * Test ZoneRules for fixed offset time-zones. + */ +@Test +public class TestFixedZoneRules { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + + private ZoneRules make(ZoneOffset offset) { + return offset.getRules(); + } + + //----------------------------------------------------------------------- + @Test(groups="implementation") + public void test_data_nullInput() { + ZoneRules test = make(OFFSET_PONE); + assertEquals(test.getOffset((Instant) null), OFFSET_PONE); + assertEquals(test.getOffset((LocalDateTime) null), OFFSET_PONE); + assertEquals(test.getValidOffsets(null).size(), 1); + assertEquals(test.getValidOffsets(null).get(0), OFFSET_PONE); + assertEquals(test.getTransition(null), null); + assertEquals(test.getStandardOffset(null), OFFSET_PONE); + assertEquals(test.getDaylightSavings(null), Duration.ZERO); + assertEquals(test.isDaylightSavings(null), false); + assertEquals(test.nextTransition(null), null); + assertEquals(test.previousTransition(null), null); + } + +} diff --git a/jdk/test/java/time/test/java/util/TestFormatter.java b/jdk/test/java/time/test/java/util/TestFormatter.java new file mode 100644 index 00000000000..54331ed2c9b --- /dev/null +++ b/jdk/test/java/time/test/java/util/TestFormatter.java @@ -0,0 +1,179 @@ +/* + * 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. + */ +package test.java.util; + +import java.time.Instant; +import java.time.temporal.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; + +import java.util.*; + +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +/* @test + * @summary Unit test for j.u.Formatter threeten date/time support + */ +@Test(groups={"implementation"}) +public class TestFormatter { + + // time + private static String[] fmtStrTime = new String[] { + "H:[%tH] I:[%1$tI] k:[%1$tk] l:[%1$tl] M:[%1$tM] S:[%1$tS] L:[%1$tL] N:[%1$tN] p:[%1$tp]", + "H:[%TH] I:[%1$TI] k:[%1$Tk] l:[%1$Tl] M:[%1$TM] S:[%1$TS] L:[%1$TL] N:[%1$TN] p:[%1$Tp]", + "R:[%tR] T:[%1$tT] r:[%1$tr]", + "R:[%TR] T:[%1$TT] r:[%1$Tr]" + }; + // date + private static String[] fmtStrDate = new String[] { + "B:[%tB] b:[%1$tb] h:[%1$th] A:[%1$tA] a:[%1$ta] C:[%1$tC] Y:[%1$tY] y:[%1$ty] j:[%1$tj] m:[%1$tm] d:[%1$td] e:[%1$te]", + "B:[%TB] b:[%1$Tb] h:[%1$Th] A:[%1$TA] a:[%1$Ta] C:[%1$TC] Y:[%1$TY] y:[%1$Ty] j:[%1$Tj] m:[%1$Tm] d:[%1$Td] e:[%1$Te]", + "D:[%tD] F:[%1$tF]", + "D:[%TD] F:[%1$TF]" + }; + + private int total = 0; + private int failure = 0; + private boolean verbose = true; + + @Test + public void test () { + + int N = 12; + //locales = Locale.getAvailableLocales(); + Locale[] locales = new Locale[] { + Locale.ENGLISH, Locale.FRENCH, Locale.JAPANESE, Locale.CHINESE}; + + Random r = new Random(); + ZonedDateTime zdt = ZonedDateTime.now(); + while (N-- > 0) { + zdt = zdt.withDayOfYear(r.nextInt(365) + 1) + .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400)); + Instant instant = zdt.toInstant(); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(instant.toEpochMilli()); + + for (Locale locale : locales) { + for (String fmtStr : fmtStrDate) { + testDate(fmtStr, locale, zdt, cal); + } + for (String fmtStr : fmtStrTime) { + testTime(fmtStr, locale, zdt, cal); + } + testZoneId(locale, zdt, cal); + testInstant(locale, instant, zdt, cal); + } + } + if (verbose) { + if (failure != 0) { + System.out.println("Total " + failure + "/" + total + " tests failed"); + } else { + System.out.println("All tests (" + total + ") PASSED"); + } + } + assertEquals(failure, 0); + } + + private String getClassName(Object o) { + Class c = o.getClass(); + return c.getName().substring(c.getPackage().getName().length() + 1); + } + + private String test(String fmtStr, Locale locale, + String expected, Object dt) { + String out = new Formatter( + new StringBuilder(), locale).format(fmtStr, dt).out().toString(); + if (verbose) { + System.out.printf("%-18s : %s%n", getClassName(dt), out); + } + if (expected != null && !out.equals(expected)) { + System.out.printf("=====>%-18s : %s [ FAILED expected: %s ]%n", + getClassName(dt), out, expected); + new RuntimeException().printStackTrace(); + failure++; + } + total++; + return out; + } + + private void printFmtStr(Locale locale, String fmtStr) { + if (verbose) { + System.out.println("--------------------"); + System.out.printf("[%s, %s]%n", locale.toString(), fmtStr); + } + } + + private void testDate(String fmtStr, Locale locale, + ZonedDateTime zdt, Calendar cal) { + 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()); + } + + private void testTime(String fmtStr, Locale locale, + ZonedDateTime zdt, Calendar cal) { + 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()); + } + + 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); + 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()); + + // datetime + zid + fmtStr = "c:[%tc] c:[%1$Tc]"; + printFmtStr(locale, fmtStr); + expected = test(fmtStr, locale, null, cal); + test(fmtStr, locale, expected, zdt); + } + + private void testInstant(Locale locale, Instant instant, + ZonedDateTime zdt, Calendar cal) { + String fmtStr = "s:[%ts] s:[%1$Ts] Q:[%1$tQ] Q:[%1$TQ]"; + printFmtStr(locale, fmtStr); + String expected = test(fmtStr, locale, null, cal); + test(fmtStr, locale, expected, instant); + test(fmtStr, locale, expected, zdt); + test(fmtStr, locale, expected, OffsetDateTime.of(zdt)); + } +} diff --git a/jdk/test/java/util/Calendar/Builder/BuilderTest.java b/jdk/test/java/util/Calendar/Builder/BuilderTest.java new file mode 100644 index 00000000000..13036d43999 --- /dev/null +++ b/jdk/test/java/util/Calendar/Builder/BuilderTest.java @@ -0,0 +1,289 @@ +/* + * 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 4745761 + * @summary Unit test for Calendar.Builder. + */ + +import java.util.*; +import static java.util.Calendar.*; + +public class BuilderTest { + private static final Locale jaJPJP = new Locale("ja", "JP", "JP"); + private static final Locale thTH = new Locale("th", "TH"); + private static final TimeZone LA = TimeZone.getTimeZone("America/Los_Angeles"); + private static final TimeZone TOKYO = TimeZone.getTimeZone("Asia/Tokyo"); + private static int error; + + public static void main(String[] args) { + TimeZone tz = TimeZone.getDefault(); + Locale loc = Locale.getDefault(); + try { + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + Locale.setDefault(Locale.US); + Calendar.Builder calb; + Calendar cal, expected; + + // set instant + calb = builder(); + long time = System.currentTimeMillis(); + cal = calb.setInstant(time).build(); + expected = new GregorianCalendar(); + expected.setTimeInMillis(time); + check(cal, expected); + + calb = builder(); + cal = calb.setInstant(new Date(time)).build(); + check(cal, expected); + + // set time zone + calb = builder(); + cal = calb.setTimeZone(LA).setInstant(time).build(); + expected = new GregorianCalendar(LA, Locale.US); + expected.setTimeInMillis(time); + check(cal, expected); + + calb = builder(); + cal = calb.setTimeZone(TOKYO).setInstant(time).build(); + expected = new GregorianCalendar(TOKYO, Locale.US); + expected.setTimeInMillis(time); + check(cal, expected); + + // set vs. setFields + calb = builder(); + cal = calb.set(YEAR, 2013).set(MONTH, JANUARY).set(DAY_OF_MONTH, 31) + .set(HOUR_OF_DAY, 10).set(MINUTE, 20).set(SECOND, 30).set(MILLISECOND, 40).build(); + expected = new GregorianCalendar(2013, JANUARY, 31, 10, 20, 30); + expected.set(MILLISECOND, 40); + check(cal, expected); + + calb = builder(); + cal = calb.setFields(YEAR, 2013, MONTH, JANUARY, DAY_OF_MONTH, 31, + HOUR_OF_DAY, 10, MINUTE, 20, SECOND, 30, MILLISECOND, 40).build(); + check(cal, expected); + + // field resolution + calb = builder(); + cal = calb.setFields(YEAR, 2013, MONTH, DECEMBER, DAY_OF_MONTH, 31, + HOUR_OF_DAY, 10, MINUTE, 20, SECOND, 30, MILLISECOND, 40) + .set(DAY_OF_YEAR, 31).build(); // DAY_OF_YEAR wins. + check(cal, expected); + + // setDate/setTimeOfDay + calb = builder(); + cal = calb.setDate(2013, JANUARY, 31).setTimeOfDay(10, 20, 30, 40).build(); + check(cal, expected); + + // week date (ISO 8601) + calb = builder().setCalendarType("iso8601"); + cal = calb.setWeekDate(2013, 1, MONDAY).setTimeOfDay(10, 20, 30).build(); + expected = getISO8601(); + expected.set(2012, DECEMBER, 31, 10, 20, 30); + check(cal, expected); + + // default YEAR == 1970 + cal = builder().setFields(MONTH, JANUARY, + DAY_OF_MONTH, 9).build(); + check(cal, new GregorianCalendar(1970, JANUARY, 9)); + + // no parameters are given. + calb = builder(); + cal = calb.build(); + expected = new GregorianCalendar(); + expected.clear(); + check(cal, expected); + + // Thai Buddhist calendar + calb = builder(); + cal = calb.setCalendarType("buddhist").setDate(2556, JANUARY, 31).build(); + expected = Calendar.getInstance(thTH); + expected.clear(); + expected.set(2556, JANUARY, 31); + check(cal, expected); + // setLocale + calb = builder(); + cal = calb.setLocale(thTH).setDate(2556, JANUARY, 31).build(); + check(cal, expected); + + // Japanese Imperial calendar + cal = builder().setCalendarType("japanese") + .setFields(YEAR, 1, DAY_OF_YEAR, 1).build(); + expected = Calendar.getInstance(jaJPJP); + expected.clear(); + expected.set(1, JANUARY, 8); + check(cal, expected); + // setLocale + calb = builder(); + cal = calb.setLocale(jaJPJP).setFields(YEAR, 1, DAY_OF_YEAR, 1).build(); + check(cal, expected); + + testExceptions(); + } finally { + // Restore default Locale and TimeZone + Locale.setDefault(loc); + TimeZone.setDefault(tz); + } + if (error > 0) { + throw new RuntimeException("Failed"); + } + } + + private static void testExceptions() { + Calendar.Builder calb; + Calendar cal; + + // NPE + try { + calb = builder().setInstant((Date)null); + noException("setInstant((Date)null)"); + } catch (NullPointerException npe) { + } + try { + calb = builder().setCalendarType(null); + noException("setCalendarType(null)"); + } catch (NullPointerException npe) { + } + try { + calb = builder().setLocale(null); + noException("setLocale(null)"); + } catch (NullPointerException npe) { + } + try { + calb = builder().setTimeZone(null); + noException("setTimeZone(null)"); + } catch (NullPointerException npe) { + } + + // IllegalArgumentException + try { + // invalid field index in set + calb = builder().set(100, 2013); + noException("set(100, 2013)"); + } catch (IllegalArgumentException e) { + } + try { + // invalid field index in setField + calb = builder().setFields(100, 2013); + noException("setFields(100, 2013)"); + } catch (IllegalArgumentException e) { + } + try { + // odd number of arguments + calb = builder().setFields(YEAR, 2013, MONTH); + noException("setFields(YEAR, 2013, MONTH)"); + } catch (IllegalArgumentException e) { + } + try { + // unknown calendar type + calb = builder().setCalendarType("foo"); + noException("setCalendarType(\"foo\")"); + } catch (IllegalArgumentException e) { + } + try { + // invalid week definition parameter + calb = builder().setWeekDefinition(8, 1); + noException("setWeekDefinition(8, 1)"); + } catch (IllegalArgumentException e) { + } + try { + // invalid week definition parameter + calb = builder().setWeekDefinition(SUNDAY, 0); + noException("setWeekDefinition(8, 1)"); + } catch (IllegalArgumentException e) { + } + + try { + // sets both instant and field parameters + calb = builder().setInstant(new Date()).setDate(2013, JANUARY, 1); + noException("setInstant(new Date()).setDate(2013, JANUARY, 1)"); + } catch (IllegalStateException e) { + } + try { + // sets both field parameters and instant + calb = builder().setDate(2013, JANUARY, 1).setInstant(new Date()); + noException("setDate(2013, JANUARY, 1).setInstant(new Date())"); + } catch (IllegalStateException e) { + } + try { + // sets inconsistent calendar types + calb = builder().setCalendarType("iso8601").setCalendarType("japanese"); + noException("setCalendarType(\"iso8601\").setCalendarType(\"japanese\")"); + } catch (IllegalStateException e) { + } + + // IllegalArgumentException in build() + calb = nonLenientBuilder().set(MONTH, 100); + checkException(calb, IllegalArgumentException.class); + calb = nonLenientBuilder().setTimeOfDay(23, 59, 70); + checkException(calb, IllegalArgumentException.class); + calb = builder().setCalendarType("japanese").setWeekDate(2013, 1, MONDAY); + checkException(calb, IllegalArgumentException.class); + } + + private static Calendar.Builder builder() { + return new Calendar.Builder(); + } + + private static Calendar.Builder nonLenientBuilder() { + return builder().setLenient(false); + } + + private static Calendar getISO8601() { + GregorianCalendar cal = new GregorianCalendar(); + cal.setFirstDayOfWeek(MONDAY); + cal.setMinimalDaysInFirstWeek(4); + cal.setGregorianChange(new Date(Long.MIN_VALUE)); + cal.clear(); + return cal; + } + + private static void check(Calendar cal, Calendar expected) { + if (!cal.equals(expected)) { + error++; + System.err.println("FAILED:"); + System.err.println("\t cal = "+cal.getTime()); + System.err.println("\texpected = "+expected.getTime()); + System.err.printf("\tcal = %s%n\texp = %s%n", cal, expected); + } + } + + private static void checkException(Calendar.Builder calb, Class exception) { + try { + Calendar cal = calb.build(); + error++; + System.err.println("expected exception: " + exception); + } catch (Exception e) { + if (!e.getClass().equals(exception)) { + error++; + System.err.println("unexpected exception: " + e.getClass() + ", expected: " + exception); + } + } + } + + private static void noException(String msg) { + error++; + System.err.println("no exception with "+msg); + } +} diff --git a/jdk/test/java/util/Calendar/CalendarTypeTest.java b/jdk/test/java/util/Calendar/CalendarTypeTest.java index 3181eac8cbd..ce36cd656b3 100644 --- a/jdk/test/java/util/Calendar/CalendarTypeTest.java +++ b/jdk/test/java/util/Calendar/CalendarTypeTest.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,7 +23,7 @@ /* * @test - * @bug 7151414 + * @bug 7151414 4745761 * @summary Unit test for calendar types */ @@ -39,20 +39,21 @@ public class CalendarTypeTest { new Locale("ja", "JP", "JP"), Locale.forLanguageTag("en-US-u-ca-japanese"), }; - static String[] types = new String[] { - "gregory", + static final String[] TYPES = new String[] { "gregory", "buddhist", - "buddhist", - "japanese", "japanese", }; + static final String[] ALIASES = new String[] { + "gregorian", + "iso8601", + }; public static void main(String[] args) { for (int i = 0; i < locales.length; i++) { Calendar cal = Calendar.getInstance(locales[i]); String type = cal.getCalendarType(); - checkValue("bad calendar type", type, types[i]); + checkValue("bad calendar type", type, TYPES[i/2]); } GregorianCalendar gcal = new GregorianCalendar(); @@ -63,6 +64,21 @@ public class CalendarTypeTest { Calendar k = new Koyomi(); checkValue("bad class name", k.getCalendarType(), k.getClass().getName()); + + Set types = Calendar.getAvailableCalendarTypes(); + if (types.size() != 3) { + throw new RuntimeException("size != 3"); + } + for (String s : TYPES) { + if (!types.contains(s)) { + throw new RuntimeException(s + " not contained"); + } + } + for (String s : ALIASES) { + if (types.contains(s)) { + throw new RuntimeException("alias " + s + " contained"); + } + } } private static void checkValue(String msg, String got, String expected) { diff --git a/jdk/test/java/util/Calendar/CldrFormatNamesTest.java b/jdk/test/java/util/Calendar/CldrFormatNamesTest.java new file mode 100644 index 00000000000..e45444d1b84 --- /dev/null +++ b/jdk/test/java/util/Calendar/CldrFormatNamesTest.java @@ -0,0 +1,178 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8004489 8006509 + * @compile -XDignore.symbol.file CldrFormatNamesTest.java + * @run main/othervm -Djava.locale.providers=CLDR CldrFormatNamesTest + * @summary Unit test for CLDR FormatData resources + */ + +import java.util.*; +import static java.util.Calendar.*; +import sun.util.locale.provider.*; + +public class CldrFormatNamesTest { + private static final Locale ARABIC = new Locale("ar"); + private static final Locale ZH_HANT = Locale.forLanguageTag("zh-Hant"); + + /* + * The first element is a Locale followed by key-value pairs + * in a FormatData resource bundle. The value type is either + * String or String[]. + */ + static final Object[][] CLDR_DATA = { + { + Locale.JAPAN, + "field.zone", "\u30bf\u30a4\u30e0\u30be\u30fc\u30f3", + "cldr.japanese.DatePatterns", new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy\u5e74M\u6708d\u65e5", + "Gyy/MM/dd", + }, + "cldr.roc.DatePatterns", new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy/MM/dd", + "Gy/MM/dd", + }, + "calendarname.buddhist", "\u30bf\u30a4\u4ecf\u6559\u66a6", + }, + { + Locale.PRC, + "field.zone", "\u533a\u57df", + "cldr.islamic.DatePatterns", new String[] { + "Gy\u5e74M\u6708d\u65e5EEEE", + "Gy\u5e74M\u6708d\u65e5", + "Gy\u5e74M\u6708d\u65e5", + "Gyy-MM-dd", + }, + "calendarname.islamic", "\u4f0a\u65af\u5170\u65e5\u5386", + }, + { + Locale.GERMANY, + "field.dayperiod", "Tagesh\u00e4lfte", + "cldr.islamic.DatePatterns", new String[] { + "EEEE d. MMMM y G", + "d. MMMM y G", + "d. MMM y G", + "d.M.y G", + }, + "calendarname.islamic", "Islamischer Kalender", + }, + }; + + // Islamic calendar symbol names in ar + private static final String[] ISLAMIC_MONTH_NAMES = { + "\u0645\u062d\u0631\u0645", + "\u0635\u0641\u0631", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0623\u0648\u0644", + "\u0631\u0628\u064a\u0639 \u0627\u0644\u0622\u062e\u0631", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0623\u0648\u0644\u0649", + "\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0622\u062e\u0631\u0629", + "\u0631\u062c\u0628", + "\u0634\u0639\u0628\u0627\u0646", + "\u0631\u0645\u0636\u0627\u0646", + "\u0634\u0648\u0627\u0644", + "\u0630\u0648 \u0627\u0644\u0642\u0639\u062f\u0629", + "\u0630\u0648 \u0627\u0644\u062d\u062c\u0629", + }; + private static final String[] ISLAMIC_ERA_NAMES = { + "", + "\u0647\u0640", + }; + + // Minguo calendar symbol names in zh_Hant + private static final String[] ROC_ERA_NAMES = { + "\u6c11\u570b\u524d", + "\u6c11\u570b", + }; + + private static int errors = 0; + + // This test is CLDR data dependent. + public static void main(String[] args) { + for (Object[] data : CLDR_DATA) { + Locale locale = (Locale) data[0]; + ResourceBundle rb = LocaleProviderAdapter.getResourceBundleBased() + .getLocaleResources(locale).getFormatData(); + for (int i = 1; i < data.length; ) { + String key = (String) data[i++]; + Object expected = data[i++]; + if (rb.containsKey(key)) { + Object value = rb.getObject(key); + if (expected instanceof String) { + if (!expected.equals(value)) { + errors++; + System.err.printf("error: key='%s', got '%s' expected '%s'%n", + key, value, expected); + } + } else if (expected instanceof String[]) { + try { + if (!Arrays.equals((Object[]) value, (Object[]) expected)) { + errors++; + System.err.printf("error: key='%s', got '%s' expected '%s'%n", + key, Arrays.asList((Object[])value), + Arrays.asList((Object[])expected)); + } + } catch (Exception e) { + errors++; + e.printStackTrace(); + } + } + } else { + errors++; + System.err.println("No resource for " + key); + } + } + } + + // test Islamic calendar names in Arabic + testSymbolNames(ARABIC, "islamic", ISLAMIC_MONTH_NAMES, MONTH, LONG, "month"); + testSymbolNames(ARABIC, "islamic", ISLAMIC_ERA_NAMES, ERA, SHORT, "era"); + + // test ROC (Minguo) calendar names in zh-Hant + testSymbolNames(ZH_HANT, "roc", ROC_ERA_NAMES, ERA, SHORT, "era"); + + if (errors > 0) { + throw new RuntimeException("test failed"); + } + } + + private static void testSymbolNames(Locale locale, String calType, String[] expected, + int field, int style, String fieldName) { + for (int i = 0; i < expected.length; i++) { + String expt = expected[i]; + String name = CalendarDataUtility.retrieveFieldValueName(calType, field, i, style, locale); + if (!expt.equals(name)) { + errors++; + System.err.printf("error: wrong %s %s name in %s: value=%d, got='%s', expected='%s'%n", + calType, fieldName, locale, i, name, expt); + } + } + } +} diff --git a/jdk/test/java/util/Formatter/Basic.sh b/jdk/test/java/util/Formatter/Basic.sh index cfa72489c98..0296d9454c8 100644 --- a/jdk/test/java/util/Formatter/Basic.sh +++ b/jdk/test/java/util/Formatter/Basic.sh @@ -23,7 +23,8 @@ # -${TESTJAVA}/bin/javac -cp ${TESTSRC} -d . ${TESTSRC}/Basic.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp ${TESTSRC} -d . \ + ${TESTSRC}/Basic.java expectPass() { if [ $1 -eq 0 ] @@ -38,7 +39,7 @@ runTest() { echo "Testing:" ${1} TZ="${1}"; export TZ echo " " $TZ - ${TESTJAVA}/bin/java Basic + ${TESTJAVA}/bin/java ${TESTVMOPTS} Basic expectPass $? } diff --git a/jdk/test/java/util/Locale/LocaleProviders.sh b/jdk/test/java/util/Locale/LocaleProviders.sh index 3cf0d4e7c69..6790f871e79 100644 --- a/jdk/test/java/util/Locale/LocaleProviders.sh +++ b/jdk/test/java/util/Locale/LocaleProviders.sh @@ -39,6 +39,10 @@ then echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi echo "TESTJAVA=${TESTJAVA}" if [ "${TESTCLASSES}" = "" ] then @@ -92,8 +96,9 @@ EOF mk ${SPIDIR}${FS}dest${FS}META-INF${FS}services${FS}java.util.spi.TimeZoneNameProvider << EOF tznp EOF -${TESTJAVA}${FS}bin${FS}javac -d ${SPIDIR}${FS}dest ${SPIDIR}${FS}src${FS}tznp.java -${TESTJAVA}${FS}bin${FS}jar cvf ${SPIDIR}${FS}tznp.jar -C ${SPIDIR}${FS}dest . +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${SPIDIR}${FS}dest \ + ${SPIDIR}${FS}src${FS}tznp.java +${COMPILEJAVA}${FS}bin${FS}jar ${TESTTOOLVMOPTS} cvf ${SPIDIR}${FS}tznp.jar -C ${SPIDIR}${FS}dest . # get the platform default locales PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale display` diff --git a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java index 160f9fbcb4f..31ef767efea 100644 --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java @@ -67,8 +67,7 @@ public class BreakIteratorProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getBundle( - "sun.text.resources.BreakIteratorInfo", target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getBreakIteratorInfo(target); String[] classNames = rb.getStringArray("BreakIteratorClasses"); boolean jreSupportsLocale = jreimplloc.contains(target); diff --git a/jdk/test/java/util/PluggableLocale/CollatorProviderTest.java b/jdk/test/java/util/PluggableLocale/CollatorProviderTest.java index 718f1658ec3..c82f6e4c8bf 100644 --- a/jdk/test/java/util/PluggableLocale/CollatorProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/CollatorProviderTest.java @@ -67,7 +67,7 @@ public class CollatorProviderTest extends ProviderTest { for (String tag : ((AvailableLanguageTags)LocaleProviderAdapter.forJRE().getCollatorProvider()).getAvailableLanguageTags()) { jreimplloc.add(Locale.forLanguageTag(tag)); } - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getCollationData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCollationData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // result object diff --git a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java index ebffc3f4f3c..b4cfaae385e 100644 --- a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java @@ -58,7 +58,7 @@ public class CurrencyNameProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - OpenListResourceBundle rb = (OpenListResourceBundle)LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (Locale test: testloc) { diff --git a/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.java b/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.java index d49b25b6acb..31ced5884ce 100644 --- a/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.java @@ -84,7 +84,7 @@ public class DateFormatProviderTest extends ProviderTest { break; } // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getDateFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays diff --git a/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java b/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java index ef07f7e3f75..f7a89b032bd 100644 --- a/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java @@ -62,7 +62,7 @@ public class DateFormatSymbolsProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getDateFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays diff --git a/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java b/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java index 7d25542d650..6753590ed6a 100644 --- a/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java @@ -61,17 +61,15 @@ public class DecimalFormatSymbolsProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getNumberFormatData(target); + Object[] data = LocaleProviderAdapter.forJRE().getLocaleResources(target).getDecimalFormatSymbolsData(); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays String[] jres = new String[2]; if (jreSupportsLocale) { - try { - String[] tmp = rb.getStringArray("NumberElements"); - jres[0] = tmp[9]; // infinity - jres[1] = tmp[10]; // NaN - } catch (MissingResourceException mre) {} + String[] tmp = (String[]) data[0]; + jres[0] = tmp[9]; // infinity + jres[1] = tmp[10]; // NaN } // result object diff --git a/jdk/test/java/util/PluggableLocale/ExecTest.sh b/jdk/test/java/util/PluggableLocale/ExecTest.sh index c01e9e82742..698d027a4af 100644 --- a/jdk/test/java/util/PluggableLocale/ExecTest.sh +++ b/jdk/test/java/util/PluggableLocale/ExecTest.sh @@ -46,6 +46,10 @@ then echo "TESTJAVA not set. Test cannot execute. Failed." exit 1 fi +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi echo "TESTJAVA=${TESTJAVA}" if [ "${TESTCLASSES}" = "" ] then @@ -99,7 +103,8 @@ esac # compile cp ${TESTSRC}${FS}ProviderTest.java . cp ${TESTSRC}${FS}$2.java . -COMPILE="${TESTJAVA}${FS}bin${FS}javac -XDignore.symbol.file -d . -classpath ${CLASSPATHARG} $2.java" +COMPILE="${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -XDignore.symbol.file -d . -classpath ${CLASSPATHARG} $2.java" echo ${COMPILE} ${COMPILE} result=$? diff --git a/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.java b/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.java index c82fab0a514..c7ec9dcd49e 100644 --- a/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.java @@ -49,7 +49,7 @@ public class LocaleNameProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - OpenListResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getLocaleNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (Locale test: testloc) { diff --git a/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.java b/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.java index 13f63fd70d5..ecb45ad7c29 100644 --- a/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.java @@ -63,16 +63,12 @@ public class NumberFormatProviderTest extends ProviderTest { void objectValidityTest() { for (Locale target: availloc) { - // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getNumberFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays String[] jreNumberPatterns = null; if (jreSupportsLocale) { - try { - jreNumberPatterns = rb.getStringArray("NumberPatterns"); - } catch (MissingResourceException mre) {} + jreNumberPatterns = LocaleProviderAdapter.forJRE().getLocaleResources(target).getNumberPatterns(); } // result object diff --git a/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java b/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java index 7ed2fc11429..29be59a645a 100644 --- a/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java @@ -52,7 +52,7 @@ public class TimeZoneNameProviderTest extends ProviderTest { for (Locale target: available) { // pure JRE implementation - OpenListResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getTimeZoneNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (String id: ids) { diff --git a/jdk/test/java/util/ServiceLoader/basic.sh b/jdk/test/java/util/ServiceLoader/basic.sh index 72d68fab7ae..5d8846a02d8 100644 --- a/jdk/test/java/util/ServiceLoader/basic.sh +++ b/jdk/test/java/util/ServiceLoader/basic.sh @@ -33,12 +33,13 @@ if [ -z "$TESTJAVA" ]; then if [ $# -lt 1 ]; then exit 1; fi TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" TESTSRC="`pwd`" TESTCLASSES="`pwd`" fi JAVA="$TESTJAVA/bin/java" -JAR="$TESTJAVA/bin/jar" +JAR="$COMPILEJAVA/bin/jar" OS=`uname -s` case "$OS" in @@ -68,7 +69,7 @@ if [ \! -d $EXTD ]; then if [ $n = 3 ]; then cp $TESTCLASSES/FooService.class $JARD fi - (cd $JARD; "$JAR" -cf ../p$n.jar *) + (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *) done mv p3.jar $EXTD diff --git a/jdk/test/java/util/TimeZone/TimeZoneDatePermissionCheck.sh b/jdk/test/java/util/TimeZone/TimeZoneDatePermissionCheck.sh index 4a295ce532f..ea40edfb055 100644 --- a/jdk/test/java/util/TimeZone/TimeZoneDatePermissionCheck.sh +++ b/jdk/test/java/util/TimeZone/TimeZoneDatePermissionCheck.sh @@ -30,10 +30,14 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA=/usr fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi -# create a test keystore and dummy cert +# create a test keystore and dummy cert. Note that we use the COMPILEJAVA +# as this test is a TimeZone test, it doesn't test keytool rm -f ${TESTCLASSES}/timezonedatetest.store -${TESTJAVA}/bin/keytool -genkeypair -alias testcert \ +${COMPILEJAVA}/bin/keytool ${TESTTOOLVMOPTS} -genkeypair -alias testcert \ -keystore ${TESTCLASSES}/timezonedatetest.store \ -storepass testpass -validity 360 \ -dname "cn=Mark Wildebeest, ou=FreeSoft, o=Red Hat, c=NL" \ @@ -41,12 +45,12 @@ ${TESTJAVA}/bin/keytool -genkeypair -alias testcert \ # create a jar file to sign with the test class in it. rm -f ${TESTCLASSES}/timezonedatetest.jar -${TESTJAVA}/bin/jar cf \ +${COMPILEJAVA}/bin/jar ${TESTTOOLVMOPTS} cf \ ${TESTCLASSES}/timezonedatetest.jar \ -C ${TESTCLASSES} TimeZoneDatePermissionCheck.class # sign it -${TESTJAVA}/bin/jarsigner \ +${COMPILEJAVA}/bin/jarsigner ${TESTTOOLVMOPTS} \ -keystore ${TESTCLASSES}/timezonedatetest.store \ -storepass testpass ${TESTCLASSES}/timezonedatetest.jar testcert diff --git a/jdk/test/java/util/concurrent/atomic/DoubleAdderDemo.java b/jdk/test/java/util/concurrent/atomic/DoubleAdderDemo.java new file mode 100644 index 00000000000..79c4cf2b61b --- /dev/null +++ b/jdk/test/java/util/concurrent/atomic/DoubleAdderDemo.java @@ -0,0 +1,164 @@ +/* + * 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. + */ + +/* + * 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/ + */ + +/* Adapted from Dougs CVS test/jsr166e/DoubleAdderDemo.java + * + * The demo is a micro-benchmark to compare synchronized access to a primitive + * double and DoubleAdder (run without any args), this restricted version simply + * exercises the basic functionality of DoubleAdder, suitable for automated + * testing (-shortrun). + */ + +/* + * @test + * @bug 8005311 + * @run main DoubleAdderDemo -shortrun + * @summary Basic test for Doubledder + */ + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.DoubleAdder; + +public class DoubleAdderDemo { + static final int INCS_PER_THREAD = 10000000; + static final int NCPU = Runtime.getRuntime().availableProcessors(); + static final int SHORT_RUN_MAX_THREADS = NCPU > 1 ? NCPU / 2 : 1; + static final int LONG_RUN_MAX_THREADS = NCPU * 2; + static final ExecutorService pool = Executors.newCachedThreadPool(); + + static final class SynchronizedDoubleAdder { + double value; + synchronized double sum() { return value; } + synchronized void add(double x) { value += x; } + } + + public static void main(String[] args) { + boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); + int maxNumThreads = shortRun ? SHORT_RUN_MAX_THREADS : LONG_RUN_MAX_THREADS; + + System.out.println("Warmup..."); + int half = NCPU > 1 ? NCPU / 2 : 1; + if (!shortRun) + syncTest(half, 1000); + adderTest(half, 1000); + + for (int reps = 0; reps < 2; ++reps) { + System.out.println("Running..."); + for (int i = 1; i <= maxNumThreads; i <<= 1) { + if (!shortRun) + syncTest(i, INCS_PER_THREAD); + adderTest(i, INCS_PER_THREAD); + } + } + pool.shutdown(); + } + + static void syncTest(int nthreads, int incs) { + System.out.print("Synchronized "); + Phaser phaser = new Phaser(nthreads + 1); + SynchronizedDoubleAdder a = new SynchronizedDoubleAdder(); + for (int i = 0; i < nthreads; ++i) + pool.execute(new SyncTask(a, phaser, incs)); + report(nthreads, incs, timeTasks(phaser), a.sum()); + } + + static void adderTest(int nthreads, int incs) { + System.out.print("DoubleAdder "); + Phaser phaser = new Phaser(nthreads + 1); + DoubleAdder a = new DoubleAdder(); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AdderTask(a, phaser, incs)); + report(nthreads, incs, timeTasks(phaser), a.sum()); + } + + static void report(int nthreads, int incs, long time, double sum) { + long total = (long)nthreads * incs; + if (sum != (double)total) + throw new Error(sum + " != " + total); + double secs = (double)time / (1000L * 1000 * 1000); + long rate = total * (1000L) / time; + System.out.printf("threads:%3d Time: %7.3fsec Incs per microsec: %4d\n", + nthreads, secs, rate); + } + + static long timeTasks(Phaser phaser) { + phaser.arriveAndAwaitAdvance(); + long start = System.nanoTime(); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + return System.nanoTime() - start; + } + + static final class AdderTask implements Runnable { + final DoubleAdder adder; + final Phaser phaser; + final int incs; + volatile double result; + AdderTask(DoubleAdder adder, Phaser phaser, int incs) { + this.adder = adder; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + DoubleAdder a = adder; + for (int i = 0; i < incs; ++i) + a.add(1.0); + result = a.sum(); + phaser.arrive(); + } + } + + static final class SyncTask implements Runnable { + final SynchronizedDoubleAdder adder; + final Phaser phaser; + final int incs; + volatile double result; + SyncTask(SynchronizedDoubleAdder adder, Phaser phaser, int incs) { + this.adder = adder; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + SynchronizedDoubleAdder a = adder; + for (int i = 0; i < incs; ++i) + a.add(1.0); + result = a.sum(); + phaser.arrive(); + } + } + +} diff --git a/jdk/test/java/util/concurrent/atomic/LongAdderDemo.java b/jdk/test/java/util/concurrent/atomic/LongAdderDemo.java new file mode 100644 index 00000000000..2e6b5fcc6a8 --- /dev/null +++ b/jdk/test/java/util/concurrent/atomic/LongAdderDemo.java @@ -0,0 +1,158 @@ +/* + * 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. + */ + +/* + * 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/ + */ + +/* Adapted from Dougs CVS test/jsr166e/LongAdderDemo.java + * + * The demo is a micro-benchmark to compare AtomicLong and LongAdder (run + * without any args), this restricted version simply exercises the basic + * functionality of LongAdder, suitable for automated testing (-shortrun). + */ + +/* + * @test + * @bug 8005311 + * @run main LongAdderDemo -shortrun + * @summary Basic test for LongAdder + */ + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAdder; + +public class LongAdderDemo { + static final int INCS_PER_THREAD = 10000000; + static final int NCPU = Runtime.getRuntime().availableProcessors(); + static final int SHORT_RUN_MAX_THREADS = NCPU > 1 ? NCPU / 2 : 1; + static final int LONG_RUN_MAX_THREADS = NCPU * 2; + static final ExecutorService pool = Executors.newCachedThreadPool(); + + public static void main(String[] args) { + boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); + int maxNumThreads = shortRun ? SHORT_RUN_MAX_THREADS : LONG_RUN_MAX_THREADS; + + System.out.println("Warmup..."); + int half = NCPU > 1 ? NCPU / 2 : 1; + if (!shortRun) + casTest(half, 1000); + adderTest(half, 1000); + + for (int reps = 0; reps < 2; ++reps) { + System.out.println("Running..."); + for (int i = 1; i <= maxNumThreads; i <<= 1) { + if (!shortRun) + casTest(i, INCS_PER_THREAD); + adderTest(i, INCS_PER_THREAD); + } + } + pool.shutdown(); + } + + static void casTest(int nthreads, int incs) { + System.out.print("AtomicLong "); + Phaser phaser = new Phaser(nthreads + 1); + AtomicLong a = new AtomicLong(); + for (int i = 0; i < nthreads; ++i) + pool.execute(new CasTask(a, phaser, incs)); + report(nthreads, incs, timeTasks(phaser), a.get()); + } + + static void adderTest(int nthreads, int incs) { + System.out.print("LongAdder "); + Phaser phaser = new Phaser(nthreads + 1); + LongAdder a = new LongAdder(); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AdderTask(a, phaser, incs)); + report(nthreads, incs, timeTasks(phaser), a.sum()); + } + + static void report(int nthreads, int incs, long time, long sum) { + long total = (long)nthreads * incs; + if (sum != total) + throw new Error(sum + " != " + total); + double secs = (double)time / (1000L * 1000 * 1000); + long rate = total * (1000L) / time; + System.out.printf("threads:%3d Time: %7.3fsec Incs per microsec: %4d\n", + nthreads, secs, rate); + } + + static long timeTasks(Phaser phaser) { + phaser.arriveAndAwaitAdvance(); + long start = System.nanoTime(); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + return System.nanoTime() - start; + } + + static final class AdderTask implements Runnable { + final LongAdder adder; + final Phaser phaser; + final int incs; + volatile long result; + AdderTask(LongAdder adder, Phaser phaser, int incs) { + this.adder = adder; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + LongAdder a = adder; + for (int i = 0; i < incs; ++i) + a.increment(); + result = a.sum(); + phaser.arrive(); + } + } + + static final class CasTask implements Runnable { + final AtomicLong adder; + final Phaser phaser; + final int incs; + volatile long result; + CasTask(AtomicLong adder, Phaser phaser, int incs) { + this.adder = adder; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + AtomicLong a = adder; + for (int i = 0; i < incs; ++i) + a.getAndIncrement(); + result = a.get(); + phaser.arrive(); + } + } + +} diff --git a/jdk/test/java/util/logging/LoggerSupplierAPIsTest.java b/jdk/test/java/util/logging/LoggerSupplierAPIsTest.java new file mode 100644 index 00000000000..4333ba18016 --- /dev/null +++ b/jdk/test/java/util/logging/LoggerSupplierAPIsTest.java @@ -0,0 +1,264 @@ +/* + * 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 8005263 + * @run testng LoggerSupplierAPIsTest + */ + +import java.util.logging.Logger; +import java.util.logging.Level; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.function.Supplier; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test(groups="unit") +public class LoggerSupplierAPIsTest { + static class CountingSupplier implements Supplier { + AtomicInteger sno = new AtomicInteger(); + + @Override + public String get() { + return "Log message " + sno.getAndIncrement(); + } + + public int getCount() { return sno.get(); } + public void reset() { sno.set(0); } + } + + static class CountingHandler extends Handler { + AtomicInteger count = new AtomicInteger(); + ArrayList ar = new ArrayList<>(); + + @Override + public void close() { reset(); } + + @Override + public void flush() { reset(); } + + @Override + public void publish(LogRecord lr) { + // Can do some more assertion here? + // System.out.println(lr.getMessage()); + count.incrementAndGet(); + } + + public int getCount() { + return count.get(); + } + + public List getLogs() { + return Collections.unmodifiableList(ar); + } + + public void reset() { + count.set(0); + ar.clear(); + } + } + + static class HelperEx extends Exception { + final Level level; + HelperEx(Level l) { level = l; } + Level getLevel() { return level; } + } + + static class SystemInfo { + public static String Java() { + return "Java: " + System.getProperty("java.version") + + " installed at " + System.getProperty("java.home"); + } + + public static String OS() { + return "OS: " + System.getProperty("os.name") + + " " + System.getProperty("os.version") + + " " + System.getProperty("os.arch"); + } + } + + static final CountingSupplier supplier = new CountingSupplier(); + static final CountingHandler handler = new CountingHandler(); + static final Logger logger; + static final Level[] levels = { Level.ALL, Level.OFF, Level.SEVERE, + Level.WARNING, Level.INFO, Level.CONFIG, + Level.FINE, Level.FINER, Level.FINEST }; + static final int[] invokes = { 7, 0, 1, 2, 3, 4, 5, 6, 7 }; + static final int[] log_count = { 10, 0, 1, 2, 3, 4, 6, 8, 10 }; + + static { + logger = Logger.getLogger("LoggerSupplierApisTest"); + logger.setUseParentHandlers(false); + logger.addHandler(handler); + } + + public void setup() { + supplier.reset(); + handler.reset(); + } + + private void testLog() { + logger.log(Level.SEVERE, supplier); + logger.log(Level.WARNING, supplier); + logger.log(Level.INFO, supplier); + logger.log(Level.CONFIG, supplier); + logger.log(Level.FINE, supplier); + logger.log(Level.FINER, supplier); + logger.log(Level.FINEST, supplier); + // Lambda expression + logger.log(Level.FINE, () -> + "Timestamp: " + System.currentTimeMillis() + + ", user home directory: " + System.getProperty("user.home")); + // Method reference + logger.log(Level.FINER, SystemInfo::Java); + logger.log(Level.FINEST, SystemInfo::OS); + } + + private void testLogThrown() { + logger.log(Level.SEVERE, new HelperEx(Level.SEVERE), supplier); + logger.log(Level.WARNING, new HelperEx(Level.WARNING), supplier); + logger.log(Level.INFO, new HelperEx(Level.INFO), supplier); + logger.log(Level.CONFIG, new HelperEx(Level.CONFIG), supplier); + logger.log(Level.FINE, new HelperEx(Level.FINE), supplier); + logger.log(Level.FINER, new HelperEx(Level.FINER), supplier); + logger.log(Level.FINEST, new HelperEx(Level.FINEST), supplier); + // Lambda expression + logger.log(Level.FINE, new HelperEx(Level.FINE), () -> + "Timestamp: " + System.currentTimeMillis() + + ", user home directory: " + System.getProperty("user.home")); + // Method reference + logger.log(Level.FINER, new HelperEx(Level.FINER), SystemInfo::Java); + logger.log(Level.FINEST, new HelperEx(Level.FINEST), SystemInfo::OS); + } + + private void testLogp() { + final String cls = getClass().getName(); + final String mtd = "testLogp"; + + logger.logp(Level.SEVERE, cls, mtd, supplier); + logger.logp(Level.WARNING, cls, mtd, supplier); + logger.logp(Level.INFO, cls, mtd, supplier); + logger.logp(Level.CONFIG, cls, mtd, supplier); + logger.logp(Level.FINE, cls, mtd, supplier); + logger.logp(Level.FINER, cls, mtd, supplier); + logger.logp(Level.FINEST, cls, mtd, supplier); + // Lambda expression + logger.logp(Level.FINE, cls, mtd, () -> + "Timestamp: " + System.currentTimeMillis() + + ", user home directory: " + System.getProperty("user.home")); + // Method reference + logger.logp(Level.FINER, cls, mtd, SystemInfo::Java); + logger.logp(Level.FINEST, cls, mtd, SystemInfo::OS); + } + + private void testLogpThrown() { + final String cls = getClass().getName(); + final String mtd = "testLogpThrown"; + + logger.logp(Level.SEVERE, cls, mtd, new HelperEx(Level.SEVERE), supplier); + logger.logp(Level.WARNING, cls, mtd, new HelperEx(Level.WARNING), supplier); + logger.logp(Level.INFO, cls, mtd, new HelperEx(Level.INFO), supplier); + logger.logp(Level.CONFIG, cls, mtd, new HelperEx(Level.CONFIG), supplier); + logger.logp(Level.FINE, cls, mtd, new HelperEx(Level.FINE), supplier); + logger.logp(Level.FINER, cls, mtd, new HelperEx(Level.FINER), supplier); + logger.logp(Level.FINEST, cls, mtd, new HelperEx(Level.FINEST), supplier); + // Lambda expression + logger.logp(Level.FINE, cls, mtd, new HelperEx(Level.FINE), () -> + "Timestamp: " + System.currentTimeMillis() + + ", user home directory: " + System.getProperty("user.home")); + // Method reference + logger.logp(Level.FINER, cls, mtd, new HelperEx(Level.FINER), SystemInfo::Java); + logger.logp(Level.FINEST, cls, mtd, new HelperEx(Level.FINEST), SystemInfo::OS); + } + + private void testLevelConvenientMethods() { + logger.severe(supplier); + logger.warning(supplier); + logger.info(supplier); + logger.config(supplier); + logger.fine(supplier); + logger.finer(supplier); + logger.finest(supplier); + // Lambda expression + logger.fine(() -> + "Timestamp: " + System.currentTimeMillis() + + ", user home directory: " + System.getProperty("user.home")); + // Method reference + logger.finer(SystemInfo::Java); + logger.finest(SystemInfo::OS); + } + + private void validate(int index, boolean thrown, String methodName) { + assertEquals(supplier.getCount(), invokes[index]); + assertEquals(handler.getCount(), log_count[index]); + // Verify associated Throwable is right + if (thrown) { + for (LogRecord r: handler.getLogs()) { + assertTrue(r.getThrown() instanceof HelperEx, "Validate Thrown"); + HelperEx e = (HelperEx) r.getThrown(); + assertEquals(r.getLevel(), e.getLevel(), "Validate Thrown Log Level"); + } + } + + if (methodName != null) { + for (LogRecord r: handler.getLogs()) { + assertEquals(r.getSourceClassName(), getClass().getName()); + assertEquals(r.getSourceMethodName(), methodName); + } + } + } + + public void verifyLogLevel() { + for (int i = 0; i < levels.length; i++) { + logger.setLevel(levels[i]); + + setup(); + testLog(); + validate(i, false, null); + + setup(); + testLogThrown(); + validate(i, true, null); + + setup(); + testLogp(); + validate(i, false, "testLogp"); + + setup(); + testLogpThrown(); + validate(i, true, "testLogpThrown"); + + setup(); + testLevelConvenientMethods(); + validate(i, false, null); + } + } +} diff --git a/jdk/test/java/util/prefs/PrefsSpi.sh b/jdk/test/java/util/prefs/PrefsSpi.sh index f1ce4f834ac..814c20978b9 100644 --- a/jdk/test/java/util/prefs/PrefsSpi.sh +++ b/jdk/test/java/util/prefs/PrefsSpi.sh @@ -39,10 +39,13 @@ if [ -z "$TESTJAVA" ]; then TESTSRC="`pwd`" TESTCLASSES="`pwd`" fi +if [ -z "$COMPILEJAVA" ]; then + COMPILEJAVA="${TESTJAVA}" +fi java="$TESTJAVA/bin/java" -javac="$TESTJAVA/bin/javac" - jar="$TESTJAVA/bin/jar" +javac="$COMPILEJAVA/bin/javac" + jar="$COMPILEJAVA/bin/jar" Die() { printf "%s\n" "$*"; exit 1; } @@ -81,9 +84,9 @@ Sys rm -rf jarDir extDir Sys mkdir -p jarDir/META-INF/services extDir echo "StubPreferencesFactory" \ > "jarDir/META-INF/services/java.util.prefs.PreferencesFactory" -Sys "$javac" -d jarDir StubPreferencesFactory.java StubPreferences.java +Sys "$javac" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d jarDir StubPreferencesFactory.java StubPreferences.java -(cd jarDir && "$jar" "cf" "../extDir/PrefsSpi.jar" ".") +(cd jarDir && "$jar" ${TESTTOOLVMOPTS} "cf" "../extDir/PrefsSpi.jar" ".") case "`uname`" in Windows*|CYGWIN* ) CPS=';';; *) CPS=':';; esac diff --git a/jdk/test/java/util/zip/ZipFile/FinalizeZipFile.java b/jdk/test/java/util/zip/ZipFile/FinalizeZipFile.java index 56ac12efb34..1c27e848280 100644 --- a/jdk/test/java/util/zip/ZipFile/FinalizeZipFile.java +++ b/jdk/test/java/util/zip/ZipFile/FinalizeZipFile.java @@ -67,9 +67,14 @@ public class FinalizeZipFile { new InstrumentedZipFile(jars[rnd.nextInt(jars.length)]).close(); // Create a ZipFile and get an input stream from it - ZipFile zf = new InstrumentedZipFile(jars[rnd.nextInt(jars.length)]); - ZipEntry ze = zf.getEntry("META-INF/MANIFEST.MF"); - InputStream is = zf.getInputStream(ze); + for (int i = 0; i < jars.length + 10; i++) { + ZipFile zf = new InstrumentedZipFile(jars[rnd.nextInt(jars.length)]); + ZipEntry ze = zf.getEntry("META-INF/MANIFEST.MF"); + if (ze != null) { + InputStream is = zf.getInputStream(ze); + break; + } + } } public static void realMain(String[] args) throws Throwable { @@ -97,4 +102,3 @@ public class FinalizeZipFile { System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} } - diff --git a/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh b/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh index ab8bb0ed8c9..c16b60ff877 100644 --- a/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh +++ b/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh @@ -35,6 +35,11 @@ then fi echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTSRC}" = "" ] then TESTSRC="." @@ -72,7 +77,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d . \ -classpath "${TESTSRC}${FS}P1.jar${PS}${TESTSRC}${FS}P2.jar" \ ${TESTSRC}${FS}FailOverTest.java diff --git a/jdk/test/javax/script/CommonSetup.sh b/jdk/test/javax/script/CommonSetup.sh index 37dff6380c3..69ed2379eda 100644 --- a/jdk/test/javax/script/CommonSetup.sh +++ b/jdk/test/javax/script/CommonSetup.sh @@ -63,6 +63,11 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then echo "TESTSRC not set. Test cannot execute. Failed." @@ -76,6 +81,6 @@ then fi JAVA="${TESTJAVA}/bin/java" -JAVAC="${TESTJAVA}/bin/javac" -JAR="${TESTJAVA}/bin/jar" +JAVAC="${COMPILEJAVA}/bin/javac" +JAR="${COMPILEJAVA}/bin/jar" diff --git a/jdk/test/javax/script/ProviderTest.sh b/jdk/test/javax/script/ProviderTest.sh index c39a9333914..e14ea48321f 100644 --- a/jdk/test/javax/script/ProviderTest.sh +++ b/jdk/test/javax/script/ProviderTest.sh @@ -38,7 +38,7 @@ fi echo "Creating JAR file ..." -$JAR -cf ${TESTCLASSES}/dummy.jar \ +$JAR ${TESTTOOLVMOPTS} -cf ${TESTCLASSES}/dummy.jar \ -C ${TESTCLASSES} DummyScriptEngine.class \ -C ${TESTCLASSES} DummyScriptEngineFactory.class \ -C "${TESTSRC}" META-INF/services/javax.script.ScriptEngineFactory diff --git a/jdk/test/javax/security/auth/Destroyable/KeyDestructionTest.java b/jdk/test/javax/security/auth/Destroyable/KeyDestructionTest.java new file mode 100644 index 00000000000..71570807e4a --- /dev/null +++ b/jdk/test/javax/security/auth/Destroyable/KeyDestructionTest.java @@ -0,0 +1,253 @@ +/* + * 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 6263419 + * @summary No way to clean the memory for a java.security.Key + */ + +import java.security.*; +import java.util.*; +import javax.crypto.*; +import javax.security.auth.Destroyable; +import javax.security.auth.DestroyFailedException; + +public class KeyDestructionTest { + public static void main(String[] args) throws Exception { + KeyPair keypair = generateKeyPair("RSA", 1024); + + // Check keys that support and have implemented key destruction + testKeyDestruction(new MyDestroyableSecretKey()); + testKeyDestruction(new MyDestroyablePrivateKey()); + + // Check keys that support but have not implemented key destruction + testNoKeyDestruction(generateSecretKey("AES", 128)); + testNoKeyDestruction(keypair.getPrivate()); + + // Check keys that do not support key destruction + try { + testKeyDestruction(keypair.getPublic()); + } catch (UnsupportedOperationException uoe) { + // not an error + System.out.println(keypair.getPublic().getClass().getName() + + " keys do not support key destruction"); + } + + System.out.println("PASSED."); + } + + // Check the behaviour of a key that implements key destruction + private static void testKeyDestruction(Key key) throws Exception { + String klass = key.getClass().getName(); + boolean hasUsable = key instanceof Usable; + + try { + key.getAlgorithm(); + key.getFormat(); + if (allZero(key.getEncoded())) { + throw new Exception("error: key destroyed prematurely"); + } + } catch (IllegalStateException ise) { + throw new Exception("error: unexpected ISE", ise); + } + + if (hasUsable) { + ((Usable) key).useKey(); + } + + destroyKey(key); + + try { + if (hasUsable) { + ((Usable) key).useKey(); + } + } catch (IllegalStateException ise) { + // not an error + } + + try { + key.getAlgorithm(); + key.getFormat(); + if (!allZero(key.getEncoded())) { + throw new Exception("error: key destroyed incorrectly"); + } + } catch (IllegalStateException ise) { + // not an error + } + + System.out.println("A " + klass + + " key has been successfully destroyed"); + } + + // Check the behaviour of a key that does not implement key destruction + private static void testNoKeyDestruction(Destroyable key) + throws Exception { + String klass = key.getClass().getName(); + + if (key.isDestroyed()) { + throw new Exception("error: a " + klass + + " key has been unexpectedly destroyed"); + } + try { + key.destroy(); + } catch (DestroyFailedException dfe) { + // not an error + + if (key.isDestroyed()) { + throw new Exception("error: a " + klass + + " key has been unexpectedly destroyed"); + } + System.out.println(klass + " keys are not destroyable"); + return; + } + throw new Exception("error: key may been unexpectedly destroyed"); + } + + private static KeyPair generateKeyPair(String algorithm, int size) + throws NoSuchAlgorithmException { + KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithm); + generator.initialize(size); + return generator.genKeyPair(); + } + + private static SecretKey generateSecretKey(String algorithm, int size) + throws NoSuchAlgorithmException { + KeyGenerator generator = KeyGenerator.getInstance(algorithm); + generator.init(size); + return generator.generateKey(); + } + + private static void destroyKey(Key key) throws Exception { + String klass = key.getClass().getName(); + + if (!(key instanceof Destroyable)) { + throw new UnsupportedOperationException(); + } + + Destroyable dKey = (Destroyable) key; + if (dKey.isDestroyed()) { + throw new Exception("error: a " + klass + + " key has already been destroyed"); + } + dKey.destroy(); + if (!dKey.isDestroyed()) { + throw new Exception("error: a " + klass + + " key has NOT been destroyed"); + } + } + + private static boolean allZero(byte[] bytes) { + int count = 0; + for (byte b : bytes) { + if (b == 0x00) { + count++; + } + } + return (bytes.length == count); + } +} + +interface Usable { + public void useKey(); +} + +class MyDestroyableSecretKey implements SecretKey, Usable { + private byte[] encoded = new byte[]{0x0F, 0x1F, 0x2F, 0x3F}; // non-zero + private boolean isDestroyed = false; + + @Override + public void useKey() { + if (isDestroyed) { + throw new IllegalStateException(); + } + } + + @Override + public String getAlgorithm() { + return "MyDestroyableSecretKey algorithm"; + } + + @Override + public String getFormat() { + return "MyDestroyableSecretKey format"; + } + + @Override + public byte[] getEncoded() { + return this.encoded; + } + + @Override + public void destroy() throws DestroyFailedException { + if (!this.isDestroyed) { + Arrays.fill(encoded, (byte) 0); + this.isDestroyed = true; + } + } + + @Override + public boolean isDestroyed() { + return this.isDestroyed; + } +} + +class MyDestroyablePrivateKey implements PrivateKey, Usable { + private byte[] encoded = new byte[]{0x4F, 0x5F, 0x6F, 0x7F}; // non-zero + private boolean isDestroyed = false; + + @Override + public void useKey() { + if (isDestroyed) { + throw new IllegalStateException(); + } + } + + @Override + public String getAlgorithm() { + return "MyDestroyablePrivateKey algorithm"; + } + + @Override + public String getFormat() { + return "MyDestroyablePrivateKey format"; + } + + @Override + public byte[] getEncoded() { + return this.encoded; + } + + @Override + public void destroy() throws DestroyFailedException { + if (!this.isDestroyed) { + Arrays.fill(encoded, (byte) 0); + this.isDestroyed = true; + } + } + + @Override + public boolean isDestroyed() { + return this.isDestroyed; + } +} diff --git a/jdk/test/javax/security/auth/Subject/doAs/Test.sh b/jdk/test/javax/security/auth/Subject/doAs/Test.sh index 65ef4531e26..73565211859 100644 --- a/jdk/test/javax/security/auth/Subject/doAs/Test.sh +++ b/jdk/test/javax/security/auth/Subject/doAs/Test.sh @@ -66,7 +66,8 @@ esac # remove any leftover built class cd ${TESTCLASSES}${FS} ${RM} Test.class -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS} ${TESTSRC}${FS}Test.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS} \ + ${TESTSRC}${FS}Test.java WD=`pwd` cd ${TESTSRC}${FS} cd $WD diff --git a/jdk/test/javax/swing/JComboBox/ShowPopupAfterHidePopupTest/ShowPopupAfterHidePopupTest.java b/jdk/test/javax/swing/JComboBox/ShowPopupAfterHidePopupTest/ShowPopupAfterHidePopupTest.java new file mode 100644 index 00000000000..e015f5ed587 --- /dev/null +++ b/jdk/test/javax/swing/JComboBox/ShowPopupAfterHidePopupTest/ShowPopupAfterHidePopupTest.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. + */ + +/* @test + @bug 8006417 + @summary JComboBox.showPopup(), hidePopup() fails in JRE 1.7 on OS X + @author Anton Litvinov +*/ + +import java.awt.*; + +import javax.swing.*; +import javax.swing.plaf.metal.*; + +import sun.awt.SunToolkit; + +public class ShowPopupAfterHidePopupTest { + private static JFrame frame = null; + private static JComboBox comboBox = null; + private static boolean popupIsVisible = false; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame("Popup Menu of JComboBox"); + comboBox = new JComboBox(new String[]{"Item1", "Item2", "Item3"}); + frame.getContentPane().add(comboBox); + frame.pack(); + frame.setVisible(true); + } + }); + final SunToolkit toolkit = (SunToolkit)Toolkit.getDefaultToolkit(); + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + comboBox.showPopup(); + comboBox.hidePopup(); + comboBox.showPopup(); + } + }); + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + popupIsVisible = comboBox.isPopupVisible(); + frame.dispose(); + } + }); + if (!popupIsVisible) { + throw new RuntimeException("Calling hidePopup() affected the next call to showPopup()."); + } + } +} diff --git a/jdk/test/javax/swing/JFileChooser/6817933/Test6817933.java b/jdk/test/javax/swing/JFileChooser/6817933/Test6817933.java new file mode 100644 index 00000000000..2b65f173a18 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6817933/Test6817933.java @@ -0,0 +1,121 @@ +/* + * 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 6817933 + * @summary Tests that HTMLEditorKit does not affect JFileChooser + * @author Sergey Malenkov + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; + +import sun.awt.SunToolkit; +import sun.swing.WindowsPlacesBar; + +public class Test6817933 { + + private static final String STYLE = "BODY {background:red}"; + private static final Color COLOR = Color.RED; + private static JFileChooser chooser; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } + catch (Exception exception) { + exception.printStackTrace(); + return; // ignore test on non-Windows machines + } + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + StyleSheet css = new StyleSheet(); + css.addRule(STYLE); + + HTMLEditorKit kit = new HTMLEditorKit(); + kit.setStyleSheet(css); + + JFrame frame = new JFrame(STYLE); + frame.add(chooser = new JFileChooser()); + frame.setSize(640, 480); + frame.setVisible(true); + } + }); + + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + toolkit.realSync(500); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + JToggleButton button = get(JToggleButton.class, + get(WindowsPlacesBar.class, chooser)); + + int width = button.getWidth(); + int height = button.getHeight() / 3; + Point point = new Point(0, height * 2); + SwingUtilities.convertPointToScreen(point, button); + width += point.x; + height += point.y; + + int count = 0; + Robot robot = new Robot(); + for (int x = point.x; x < width; x++) { + for (int y = point.y; y < height; y++) { + count += COLOR.equals(robot.getPixelColor(x, y)) ? -2 : 1; + } + } + if (count < 0) { + throw new Exception("TEST ERROR: a lot of red pixels"); + } + } + catch (Exception exception) { + throw new Error(exception); + } + finally { + SwingUtilities.getWindowAncestor(chooser).dispose(); + } + } + }); + } + + private static T get(Class type, Container container) { + Component component = container.getComponent(0); + if (!type.isAssignableFrom(component.getClass())) { + throw new IllegalStateException("expected " + type + "; expected " + component.getClass()); + } + return (T) component; + } +} diff --git a/jdk/test/javax/swing/JTree/8003400/Test8003400.java b/jdk/test/javax/swing/JTree/8003400/Test8003400.java new file mode 100644 index 00000000000..f2102f8b1e4 --- /dev/null +++ b/jdk/test/javax/swing/JTree/8003400/Test8003400.java @@ -0,0 +1,109 @@ +/* + * 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 8003400 + * @summary Tests that JTree shows the last row + * @author Sergey Malenkov + * @run main/othervm Test8003400 + * @run main/othervm Test8003400 reverse + * @run main/othervm Test8003400 system + * @run main/othervm Test8003400 system reverse + */ + +import sun.awt.SunToolkit; + +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.tree.DefaultMutableTreeNode; + +public class Test8003400 { + + private static final String TITLE = "Test JTree with a large model"; + private static List OBJECTS = Arrays.asList(TITLE, "x", "y", "z"); + private static JScrollPane pane; + + public static void main(String[] args) throws Exception { + for (String arg : args) { + if (arg.equals("reverse")) { + Collections.reverse(OBJECTS); + } + if (arg.equals("system")) { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + } + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + JTree tree = new JTree(root); + tree.setLargeModel(true); + tree.setRowHeight(16); + + JFrame frame = new JFrame(TITLE); + frame.add(pane = new JScrollPane(tree)); + frame.setSize(200, 100); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setVisible(true); + + for (String object : OBJECTS) { + root.add(new DefaultMutableTreeNode(object)); + } + tree.expandRow(0); + } + }); + + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + toolkit.realSync(500); + new Robot().keyPress(KeyEvent.VK_END); + toolkit.realSync(500); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + JTree tree = (JTree) pane.getViewport().getView(); + Rectangle inner = tree.getRowBounds(tree.getRowCount() - 1); + Rectangle outer = SwingUtilities.convertRectangle(tree, inner, pane); + outer.y += tree.getRowHeight() - 1 - pane.getVerticalScrollBar().getHeight(); + // error reporting only for automatic testing + if (null != System.getProperty("test.src", null)) { + SwingUtilities.getWindowAncestor(pane).dispose(); + if (outer.y != 0) { + throw new Error("TEST FAILED: " + outer.y); + } + } + } + }); + } +} diff --git a/jdk/test/javax/swing/JTree/8004298/bug8004298.java b/jdk/test/javax/swing/JTree/8004298/bug8004298.java new file mode 100644 index 00000000000..3d0ca5c00bc --- /dev/null +++ b/jdk/test/javax/swing/JTree/8004298/bug8004298.java @@ -0,0 +1,116 @@ +/* + * 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 8004298 + * @summary NPE in WindowsTreeUI.ensureRowsAreVisible + * @author Alexander Scherbatiy + * @library ../../regtesthelpers + * @build Util + * @run main bug8004298 + */ + +import java.awt.*; +import java.awt.event.InputEvent; +import javax.swing.*; +import javax.swing.tree.*; +import java.util.concurrent.Callable; +import sun.awt.SunToolkit; +import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; +import com.sun.java.swing.plaf.windows.WindowsTreeUI; + +public class bug8004298 { + + private static JTree tree; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(50); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + UIManager.setLookAndFeel(new WindowsLookAndFeel()); + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + createAndShowGUI(); + } + }); + + toolkit.realSync(); + + Point point = Util.invokeOnEDT(new Callable() { + + @Override + public Point call() throws Exception { + Rectangle rect = tree.getRowBounds(2); + Point p = new Point(rect.x + rect.width / 2, rect.y + rect.height / 2); + SwingUtilities.convertPointToScreen(p, tree); + return p; + } + }); + + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + toolkit.realSync(); + + } + + private static void createAndShowGUI() { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); + root.add(new DefaultMutableTreeNode("colors")); + DefaultMutableTreeNode sports = new DefaultMutableTreeNode("sports"); + sports.add(new DefaultMutableTreeNode("basketball")); + sports.add(new DefaultMutableTreeNode("football")); + root.add(sports); + + tree = new JTree(root); + tree.setUI(new NullReturningTreeUI()); + + frame.getContentPane().add(tree); + frame.pack(); + frame.setVisible(true); + + } + + private static final class NullReturningTreeUI extends WindowsTreeUI { + + @Override + public Rectangle getPathBounds(JTree tree, TreePath path) { + // the method can return null and callers have to be ready for + // that. Simulate the case by returning null for unknown reason. + if (path != null && path.toString().contains("football")) { + return null; + } + + return super.getPathBounds(tree, path); + } + } +} \ No newline at end of file diff --git a/jdk/test/javax/swing/SpringLayout/4726194/bug4726194.java b/jdk/test/javax/swing/SpringLayout/4726194/bug4726194.java new file mode 100644 index 00000000000..2516910e07c --- /dev/null +++ b/jdk/test/javax/swing/SpringLayout/4726194/bug4726194.java @@ -0,0 +1,161 @@ +/* + * 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 4726194 7124209 + * @summary Tests for 4726194 + * @author Phil Milne + */ +import java.awt.*; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.List; +import javax.swing.*; + +public class bug4726194 { + + private static String[] hConstraints = {SpringLayout.WEST, "Width", SpringLayout.EAST, SpringLayout.HORIZONTAL_CENTER}; + private static String[] vConstraints = {SpringLayout.NORTH, "Height", SpringLayout.SOUTH, SpringLayout.VERTICAL_CENTER, SpringLayout.BASELINE}; + private static int[] FAIL = new int[3]; + private static boolean TEST_DUPLICATES = false; + + public static void main(String[] args) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + int minLevel = 2; + int maxLevel = 2; + for (int i = minLevel; i <= maxLevel; i++) { + test(i, true); + test(i, false); + } + } + }); + } catch (InterruptedException | InvocationTargetException ex) { + ex.printStackTrace(); + throw new RuntimeException("FAILED: SwingUtilities.invokeAndWait method failed!"); + } + } + + public static void test(int level, boolean horizontal) { + List result = new ArrayList(); + String[] constraints = horizontal ? hConstraints : vConstraints; + test(level, constraints, result, Arrays.asList(new Object[level])); + JTextField tf = new JTextField(""); + tf.setFont(new Font("Dialog", Font.PLAIN, 6)); + System.out.print("\t\t"); + for (int j = 0; j < constraints.length; j++) { + String constraint = constraints[j]; + System.out.print(constraint + " ".substring(constraint.length())); + } + System.out.println(""); + for (int i = 0; i < result.size(); i++) { + SpringLayout.Constraints c = new SpringLayout.Constraints(tf); + List cc = (List) result.get(i); + for (int j = 0; j < cc.size(); j++) { + String constraint = (String) cc.get(j); + c.setConstraint(constraint, Spring.constant((j + 1) * 10)); + } + System.out.print(" Input:\t\t"); + for (int j = 0; j < constraints.length; j++) { + String constraint = constraints[j]; + int jj = cc.indexOf(constraint); + String val = cc.contains(constraint) ? Integer.toString((jj + 1) * 10) : "?"; + System.out.print(val + "\t\t"); + } + System.out.println(""); + System.out.print("Output:\t\t"); + for (int j = 0; j < constraints.length; j++) { + String constraint = constraints[j]; + Spring spring = c.getConstraint(constraint); + String springVal = (spring == null) ? "?" : Integer.toString(spring.getValue()); + System.out.print(springVal); + System.out.print("\t\t"); + } + for (int j = 0; j < cc.size(); j++) { + String constraint = (String) cc.get(j); + Spring con = c.getConstraint(constraint); + if (con == null || con.getValue() != (j + 1) * 10) { + throw new RuntimeException("Values are wrong!!! "); + } + } + if (horizontal) { + int[] a1 = getValues(c, new String[]{SpringLayout.WEST, SpringLayout.WIDTH, SpringLayout.EAST}); + if (a1[0] + a1[1] != a1[2]) { + throw new RuntimeException("WEST + WIDTH != EAST!!! "); + } + int[] a2 = getValues(c, new String[]{SpringLayout.WEST, SpringLayout.WIDTH, SpringLayout.HORIZONTAL_CENTER}); + if (a2[0] + a2[1] / 2 != a2[2]) { + throw new RuntimeException("WEST + WIDTH/2 != HORIZONTAL_CENTER!!! "); + } + } else { + int[] a3 = getValues(c, new String[]{SpringLayout.NORTH, SpringLayout.HEIGHT, SpringLayout.SOUTH}); + if (a3[0] + a3[1] != a3[2]) { + throw new RuntimeException("NORTH + HEIGHT != SOUTH!!! "); + } + int[] a4 = getValues(c, new String[]{SpringLayout.NORTH, SpringLayout.HEIGHT, SpringLayout.VERTICAL_CENTER}); + int vcDiff = Math.abs(a4[0] + a4[1] / 2 - a4[2]); + if (vcDiff > 1) { + throw new RuntimeException("NORTH + HEIGHT/2 != VERTICAL_CENTER!!! "); + } + int[] a5 = getValues(c, new String[]{SpringLayout.NORTH, SpringLayout.BASELINE, SpringLayout.SOUTH}); + if (a5[0] > a5[1] != a5[1] > a5[2]) { + throw new RuntimeException("BASELINE is not in the range: [NORTH, SOUTH]!!!"); + } + } + System.out.println(""); + } + System.out.println(""); + } + + private static int[] getValues(SpringLayout.Constraints con, String[] cNames) { + int[] result = new int[cNames.length]; + for (int i = 0; i < cNames.length; i++) { + String name = cNames[i]; + Spring s = con.getConstraint(name); + if (s == null) { + System.out.print("Warning: " + name + " is undefined. "); + return FAIL; + } + result[i] = s.getValue(); + } + return result; + } + + public static void test(int level, String[] constraints, List result, List soFar) { + if (level == 0) { + result.add(soFar); + return; + } + for (int i = 0; i < constraints.length; i++) { + if (soFar.contains(constraints[i]) && !TEST_DUPLICATES) { + continue; + } + List child = new ArrayList(soFar); + child.set(level - 1, constraints[i]); + test(level - 1, constraints, result, child); + } + } +} diff --git a/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh b/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh index 3efcce9b4e0..b562afa4323 100644 --- a/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh +++ b/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh @@ -46,6 +46,9 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi # set platform-dependent variables OS=`uname -s` @@ -74,7 +77,7 @@ esac # the test code cd ${TESTCLASSES} -${TESTJAVA}${FS}bin${FS}jar -cvf Ext_AllPolicy.jar Ext_AllPolicy.class +${COMPILEJAVA}${FS}bin${FS}jar ${TESTTOOLVMOPTS} -cvf Ext_AllPolicy.jar Ext_AllPolicy.class rm Ext_AllPolicy.class ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \ diff --git a/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.sh b/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.sh index dfc4a85ad5c..fe1fec654a7 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.sh @@ -90,7 +90,7 @@ createPasswordFile ${PASSWD} # Compile test -${TESTJAVA}/bin/javac -d ${TESTCLASSES} ${TESTCLASSES}/Null.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES} ${TESTCLASSES}/Null.java JAVA=${TESTJAVA}/bin/java diff --git a/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh b/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh index 0fa765409b6..022aa2a4d26 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh @@ -88,7 +88,7 @@ createSSLConfigFile ${SSL} ${TESTSRC}/ssl/keystore # Compile test -${TESTJAVA}/bin/javac -d ${TESTCLASSES} ${TESTCLASSES}/Dummy.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES} ${TESTCLASSES}/Dummy.java JAVA=${TESTJAVA}/bin/java CLASSPATH=${TESTCLASSES} diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh index 2021381c247..e2e7598a994 100644 --- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh @@ -51,7 +51,8 @@ _compile(){ rm -f ${_testclasses}/JMXStartStopTest.class # Compile testcase - ${TESTJAVA}/bin/javac -d ${_testclasses} JMXStartStopDoSomething.java JMXStartStopTest.java + ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${_testclasses} \ + JMXStartStopDoSomething.java JMXStartStopTest.java if [ ! -f ${_testclasses}/JMXStartStopTest.class ] then @@ -82,7 +83,7 @@ _app_start(){ } _get_pid(){ - ${TESTJAVA}/bin/jps | sed -n "/JMXStartStopDoSomething/s/ .*//p" + ${COMPILEJAVA}/bin/jps ${TESTTOOLVMOPTS} | sed -n "/JMXStartStopDoSomething/s/ .*//p" } _app_stop(){ @@ -115,7 +116,7 @@ _testme(){ _jcmd(){ - ${TESTJAVA}/bin/jcmd JMXStartStopDoSomething $* > /dev/null 2>/dev/null + ${TESTJAVA}/bin/jcmd ${TESTTOOLVMOPTS} JMXStartStopDoSomething $* > /dev/null 2>/dev/null } _echo(){ @@ -445,7 +446,7 @@ test_11(){ _jcmd ManagementAgent.stop - pid=`${TESTJAVA}/bin/jps | sed -n "/JMXStartStopDoSomething/s/ .*//p"` + pid=`${COMPILEJAVA}/bin/jps ${TESTTOOLVMOPTS} | sed -n "/JMXStartStopDoSomething/s/ .*//p"` res2=`_testme local ${pid}` if [ "${res1}" = "OK_CONN" -a "${res2}" = "OK_CONN" ] @@ -528,6 +529,7 @@ if [ ! -x "${TESTJAVA}/bin/jcmd" ] then echo "${TESTJAVA}/bin/jcmd" echo "Doesn't exist or not an executable" + exit fi diff --git a/jdk/test/sun/misc/URLClassPath/JarLoaderTest.java b/jdk/test/sun/misc/URLClassPath/JarLoaderTest.java new file mode 100644 index 00000000000..cd9cbc88bf4 --- /dev/null +++ b/jdk/test/sun/misc/URLClassPath/JarLoaderTest.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. + */ + +/* + * Portions Copyright (c) 2013 IBM Corporation + */ + +/* @test + * @bug 7183373 + * @summary URLClassLoader fails to close handles to Jar files opened during + * getResource() + */ + +import java.io.*; +import java.net.*; +import java.util.zip.*; + +public class JarLoaderTest { + public static void main(String[] args) throws Exception { + // Create a JAR file + File f = new File("urlcl" + 1 + ".jar"); + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(f)); + + // add a file + zos.putNextEntry(new ZipEntry("TestResource")); + byte[] b = "This is a test resource".getBytes(); + zos.write(b, 0, b.length); + zos.close(); + + // Load the file using cl.getResource() + URLClassLoader cl = new URLClassLoader(new URL[] { new URL("jar:" + + f.toURI().toURL() + "!/")}, null); + cl.getResource("TestResource"); + + // Close the class loader - this should free up all of its Closeables, + // including the JAR file + cl.close(); + + // Try to delete the JAR file + f.delete(); + + // Check to see if the file was deleted + if (f.exists()) { + System.out.println( + "Test FAILED: Closeables failed to close handle to jar file"); + // Delete the jar using a workaround + for (URL u : cl.getURLs()) { + if (u.getProtocol().equals("jar")) { + ((JarURLConnection)u.openConnection()).getJarFile().close(); + } + f.delete(); + } + throw new RuntimeException("File could not be deleted"); + } else { + System.out.println("Test PASSED"); + } + } +} diff --git a/jdk/test/sun/net/www/MarkResetTest.sh b/jdk/test/sun/net/www/MarkResetTest.sh index 542bfe4b179..c998bcffef2 100644 --- a/jdk/test/sun/net/www/MarkResetTest.sh +++ b/jdk/test/sun/net/www/MarkResetTest.sh @@ -46,7 +46,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}MarkResetTest.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}MarkResetTest.java # ftp server used by the test requires the file to be present # in this directory diff --git a/jdk/test/sun/net/www/http/HttpClient/RetryPost.sh b/jdk/test/sun/net/www/http/HttpClient/RetryPost.sh index fc563c83b16..17d08cd30b0 100644 --- a/jdk/test/sun/net/www/http/HttpClient/RetryPost.sh +++ b/jdk/test/sun/net/www/http/HttpClient/RetryPost.sh @@ -47,7 +47,7 @@ case "$OS" in esac # compile -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}RetryPost.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}RetryPost.java # run with no option specified. Should retry POST request. ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} RetryPost diff --git a/jdk/test/sun/net/www/protocol/http/ProxyTunnelServer.java b/jdk/test/sun/net/www/protocol/http/ProxyTunnelServer.java index 96d9e9ef91a..a19d89ca101 100644 --- a/jdk/test/sun/net/www/protocol/http/ProxyTunnelServer.java +++ b/jdk/test/sun/net/www/protocol/http/ProxyTunnelServer.java @@ -31,6 +31,7 @@ import java.io.*; import java.net.*; +import java.util.Base64; import javax.net.ssl.*; import javax.net.ServerSocketFactory; import sun.net.www.*; @@ -295,10 +296,8 @@ public class ProxyTunnelServer extends Thread { String recvdUserPlusPass = authInfo.substring(ind + 1).trim(); // extract encoded (username:passwd if (userPlusPass.equals( - new String( - (new sun.misc.BASE64Decoder()). - decodeBuffer(recvdUserPlusPass) - ))) { + new String(Base64.getDecoder().decode(recvdUserPlusPass)) + )) { matched = true; } } catch (Exception e) { diff --git a/jdk/test/sun/net/www/protocol/jar/B5105410.sh b/jdk/test/sun/net/www/protocol/jar/B5105410.sh index 1fdbdd58ff8..f47ca5ed99d 100644 --- a/jdk/test/sun/net/www/protocol/jar/B5105410.sh +++ b/jdk/test/sun/net/www/protocol/jar/B5105410.sh @@ -50,6 +50,6 @@ case "$OS" in esac cp ${TESTSRC}${FS}foo2.jar . -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}B5105410.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}B5105410.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} B5105410 diff --git a/jdk/test/sun/net/www/protocol/jar/jarbug/run.sh b/jdk/test/sun/net/www/protocol/jar/jarbug/run.sh index 72a11681d1c..5f039b97c93 100644 --- a/jdk/test/sun/net/www/protocol/jar/jarbug/run.sh +++ b/jdk/test/sun/net/www/protocol/jar/jarbug/run.sh @@ -59,17 +59,17 @@ esac mkdir -p ${DEST}${FS}jar1 cd ${TESTSRC}${FS}etc${FS}jar1 cp -r . ${DEST}${FS}jar1 -${TESTJAVA}${FS}bin${FS}javac -d ${DEST}${FS}jar1 \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${DEST}${FS}jar1 \ ${TESTSRC}${FS}src${FS}jar1${FS}LoadResourceBundle.java -${TESTJAVA}${FS}bin${FS}javac -d ${DEST}${FS}jar1 \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${DEST}${FS}jar1 \ ${TESTSRC}${FS}src${FS}jar1${FS}GetResource.java cd ${DEST}${FS}jar1 -${TESTJAVA}${FS}bin${FS}jar cfM jar1.jar jar1 res1.txt +${COMPILEJAVA}${FS}bin${FS}jar ${TESTTOOLVMOPTS} cfM jar1.jar jar1 res1.txt mv jar1.jar .. # # build the test sources and run them # -${TESTJAVA}${FS}bin${FS}javac -d ${DEST} ${TESTSRC}${FS}src${FS}test${FS}*.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${DEST} ${TESTSRC}${FS}src${FS}test${FS}*.java cd ${DEST} ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} RunAllTests result=$? diff --git a/jdk/test/sun/security/krb5/config/dns.sh b/jdk/test/sun/security/krb5/config/dns.sh index 5c85f8aa776..71b2addc2d5 100644 --- a/jdk/test/sun/security/krb5/config/dns.sh +++ b/jdk/test/sun/security/krb5/config/dns.sh @@ -26,16 +26,19 @@ # @summary Krb5LoginModule config class does not return proper KDC list from DNS # +env + if [ "${TESTJAVA}" = "" ] ; then JAVAC_CMD=`which javac` TESTJAVA=`dirname $JAVAC_CMD`/.. + COMPILEJAVA="${TESTJAVA}" fi if [ "${TESTSRC}" = "" ] ; then TESTSRC="." fi -$TESTJAVA/bin/javac -d . \ - ${TESTSRC}/NamingManager.java ${TESTSRC}/DNS.java +$COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}/NamingManager.java ${TESTSRC}/DNS.java $TESTJAVA/bin/java -Xbootclasspath/p:. DNS diff --git a/jdk/test/sun/security/krb5/runNameEquals.sh b/jdk/test/sun/security/krb5/runNameEquals.sh index 1fea3620e19..1c3dca34a3b 100644 --- a/jdk/test/sun/security/krb5/runNameEquals.sh +++ b/jdk/test/sun/security/krb5/runNameEquals.sh @@ -43,6 +43,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + NATIVE=false # set platform-dependent variables @@ -73,7 +77,7 @@ esac TEST=Krb5NameEquals -${TESTJAVA}${FILESEP}bin${FILESEP}javac \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -d ${TESTCLASSES}${FILESEP} \ ${TESTSRC}${FILESEP}${TEST}.java diff --git a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh index 77e258e4cda..6e7ffa302b0 100644 --- a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh +++ b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh @@ -39,7 +39,7 @@ case "$OS" in # # execute test program - rely on it to exit if platform unsupported - ${TESTJAVA}/bin/javac -d . ${TESTSRC}\\IsSunMSCAPIAvailable.java + ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}\\IsSunMSCAPIAvailable.java ${TESTJAVA}/bin/java ${TESTVMOPTS} IsSunMSCAPIAvailable exit ;; diff --git a/jdk/test/sun/security/pkcs11/KeyStore/Basic.sh b/jdk/test/sun/security/pkcs11/KeyStore/Basic.sh index 452b6290e4a..ab7045f12a9 100644 --- a/jdk/test/sun/security/pkcs11/KeyStore/Basic.sh +++ b/jdk/test/sun/security/pkcs11/KeyStore/Basic.sh @@ -54,9 +54,13 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA="/net/radiant/export1/charlie/mustang/build/solaris-sparc" fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo echo COMPILEJAVA=${COMPILEJAVA} echo "" # get command from input args - @@ -163,7 +167,7 @@ fi # compile test if [ "${RECOMPILE}" = "yes" ] ; then - ${TESTJAVA}${FS}bin${FS}javac \ + ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FS}..${PS}${TESTSRC}${FS}loader.jar \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}Basic.java diff --git a/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh b/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh index d0996c1823a..eb340c919d5 100644 --- a/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh +++ b/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh @@ -40,9 +40,13 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA="/net/radiant/export1/charlie/mustang/build/solaris-sparc" fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo COMPILEJAVA=${COMPILEJAVA} echo "" OS=`uname -s` @@ -121,7 +125,7 @@ ${CP} ${TESTSRC}${FS}ClientAuthData${FS}key3.db ${TESTCLASSES} ${CHMOD} +w ${TESTCLASSES}${FS}key3.db # compile test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FS}..${PS}${TESTSRC}${FS}loader.jar \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}ClientAuth.java diff --git a/jdk/test/sun/security/pkcs11/KeyStore/Solaris.sh b/jdk/test/sun/security/pkcs11/KeyStore/Solaris.sh index 5ec1ac2ec95..302ce50b3ed 100644 --- a/jdk/test/sun/security/pkcs11/KeyStore/Solaris.sh +++ b/jdk/test/sun/security/pkcs11/KeyStore/Solaris.sh @@ -53,9 +53,13 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA="/net/radiant/export1/charlie/mustang/build/solaris-sparc" fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo COMPILEJAVA=${COMPILEJAVA} echo "" # get command from input args - @@ -133,7 +137,7 @@ ${CHMOD} 600 ${TESTCLASSES}${FS}pkcs11_softtoken${FS}objstore_info if [ "${RECOMPILE}" = "yes" ] ; then cd ${TESTCLASSES} ${RM} *.class - ${TESTJAVA}${FS}bin${FS}javac \ + ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FS}..${PS}${TESTSRC}${FS}loader.jar \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}Basic.java diff --git a/jdk/test/sun/security/pkcs11/Provider/ConfigQuotedString.sh b/jdk/test/sun/security/pkcs11/Provider/ConfigQuotedString.sh index 1a749d89490..b1cf0d9082c 100644 --- a/jdk/test/sun/security/pkcs11/Provider/ConfigQuotedString.sh +++ b/jdk/test/sun/security/pkcs11/Provider/ConfigQuotedString.sh @@ -41,9 +41,13 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA="/net/radiant/export1/charlie/mustang/build/solaris-sparc" fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo COMPILEJAVA=${COMPILEJAVA} echo "" # let java test exit if platform unsupported @@ -92,7 +96,7 @@ esac # compile test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FS}.. \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}ConfigQuotedString.java diff --git a/jdk/test/sun/security/pkcs11/Provider/Login.sh b/jdk/test/sun/security/pkcs11/Provider/Login.sh index 6b37ef837d2..cbbcb06d318 100644 --- a/jdk/test/sun/security/pkcs11/Provider/Login.sh +++ b/jdk/test/sun/security/pkcs11/Provider/Login.sh @@ -42,9 +42,13 @@ fi if [ "${TESTJAVA}" = "" ] ; then TESTJAVA="/net/radiant/export1/charlie/mustang/build/solaris-sparc" fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi echo TESTSRC=${TESTSRC} echo TESTCLASSES=${TESTCLASSES} echo TESTJAVA=${TESTJAVA} +echo COMPILEJAVA=${COMPILEJAVA} echo "" # let java test exit if platform unsupported @@ -101,7 +105,7 @@ ${CHMOD} +w ${TESTCLASSES}${FS}key3.db # compile test -${TESTJAVA}${FS}bin${FS}javac \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ -classpath ${TESTSRC}${FS}.. \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}Login.java diff --git a/jdk/test/sun/security/pkcs12/StorePasswordTest.java b/jdk/test/sun/security/pkcs12/StorePasswordTest.java new file mode 100644 index 00000000000..fc2f77c51c1 --- /dev/null +++ b/jdk/test/sun/security/pkcs12/StorePasswordTest.java @@ -0,0 +1,92 @@ +/* + * 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 8005408 + * @summary KeyStore API enhancements + */ + +import java.io.*; +import java.security.*; +import java.util.*; +import javax.crypto.*; +import javax.crypto.spec.*; +import java.security.spec.InvalidKeySpecException; + +// Store a password in a keystore and retrieve it again. + +public class StorePasswordTest { + private final static String DIR = System.getProperty("test.src", "."); + private static final char[] PASSWORD = "passphrase".toCharArray(); + private static final String KEYSTORE = "pwdstore.p12"; + private static final String ALIAS = "my password"; + private static final String USER_PASSWORD = "hello1"; + + public static void main(String[] args) throws Exception { + + new File(KEYSTORE).delete(); + + try { + + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(null, null); + + // Set entry + keystore.setEntry(ALIAS, + new KeyStore.SecretKeyEntry(convertPassword(USER_PASSWORD)), + new KeyStore.PasswordProtection(PASSWORD)); + + System.out.println("Storing keystore to: " + KEYSTORE); + keystore.store(new FileOutputStream(KEYSTORE), PASSWORD); + + System.out.println("Loading keystore from: " + KEYSTORE); + keystore.load(new FileInputStream(KEYSTORE), PASSWORD); + System.out.println("Loaded keystore with " + keystore.size() + + " entries"); + KeyStore.Entry entry = keystore.getEntry(ALIAS, + new KeyStore.PasswordProtection(PASSWORD)); + System.out.println("Retrieved entry: " + entry); + + SecretKey key = (SecretKey) keystore.getKey(ALIAS, PASSWORD); + SecretKeyFactory factory = + SecretKeyFactory.getInstance(key.getAlgorithm()); + PBEKeySpec keySpec = + (PBEKeySpec) factory.getKeySpec(key, PBEKeySpec.class); + char[] pwd = keySpec.getPassword(); + System.out.println("Recovered credential: " + new String(pwd)); + + if (!Arrays.equals(USER_PASSWORD.toCharArray(), pwd)) { + throw new Exception("Failed to recover the stored password"); + } + } finally { + new File(KEYSTORE).delete(); + } + } + + private static SecretKey convertPassword(String password) + throws NoSuchAlgorithmException, InvalidKeySpecException { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); + return factory.generateSecret(new PBEKeySpec(password.toCharArray())); + } +} diff --git a/jdk/test/sun/security/pkcs12/StoreSecretKeyTest.java b/jdk/test/sun/security/pkcs12/StoreSecretKeyTest.java new file mode 100644 index 00000000000..f002ef7506a --- /dev/null +++ b/jdk/test/sun/security/pkcs12/StoreSecretKeyTest.java @@ -0,0 +1,105 @@ +/* + * 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 8005408 + * @summary KeyStore API enhancements + */ + +import java.io.*; +import java.security.*; +import java.util.*; +import javax.crypto.*; +import javax.crypto.spec.*; + +// Store a secret key in a keystore and retrieve it again. + +public class StoreSecretKeyTest { + private final static String DIR = System.getProperty("test.src", "."); + private static final char[] PASSWORD = "passphrase".toCharArray(); + private static final String KEYSTORE = "keystore.p12"; + private static final String ALIAS = "my secret key"; + + public static void main(String[] args) throws Exception { + + // Skip test if AES is unavailable + try { + SecretKeyFactory.getInstance("AES"); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("AES is unavailable. Skipping test..."); + return; + } + + new File(KEYSTORE).delete(); + + try { + + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(null, null); + + // Set entry + keystore.setEntry(ALIAS, + new KeyStore.SecretKeyEntry(generateSecretKey("AES", 128)), + new KeyStore.PasswordProtection(PASSWORD)); + + System.out.println("Storing keystore to: " + KEYSTORE); + keystore.store(new FileOutputStream(KEYSTORE), PASSWORD); + + System.out.println("Loading keystore from: " + KEYSTORE); + keystore.load(new FileInputStream(KEYSTORE), PASSWORD); + System.out.println("Loaded keystore with " + keystore.size() + + " entries"); + KeyStore.Entry entry = keystore.getEntry(ALIAS, + new KeyStore.PasswordProtection(PASSWORD)); + System.out.println("Retrieved entry: " + entry); + + if (entry instanceof KeyStore.SecretKeyEntry) { + System.out.println("Retrieved secret key entry: " + + entry); + } else { + throw new Exception("Not a secret key entry"); + } + } finally { + new File(KEYSTORE).delete(); + } + } + + private static SecretKey generateSecretKey(String algorithm, int size) + throws NoSuchAlgorithmException { + + // Failover to DES if the requested secret key factory is unavailable + SecretKeyFactory keyFactory; + try { + keyFactory = SecretKeyFactory.getInstance(algorithm); + } catch (NoSuchAlgorithmException nsae) { + keyFactory = SecretKeyFactory.getInstance("DES"); + algorithm = "DES"; + size = 56; + } + + KeyGenerator generator = KeyGenerator.getInstance(algorithm); + generator.init(size); + return generator.generateKey(); + } +} diff --git a/jdk/test/sun/security/pkcs12/StoreTrustedCertTest.java b/jdk/test/sun/security/pkcs12/StoreTrustedCertTest.java new file mode 100644 index 00000000000..a1481749d7e --- /dev/null +++ b/jdk/test/sun/security/pkcs12/StoreTrustedCertTest.java @@ -0,0 +1,117 @@ +/* + * 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 8005408 + * @summary KeyStore API enhancements + */ + +import java.io.*; +import java.security.*; +import java.security.cert.*; +import java.util.*; +import java.security.cert.Certificate; +import javax.crypto.*; +import javax.crypto.spec.*; + +// Store a trusted certificate in a keystore and retrieve it again. + +public class StoreTrustedCertTest { + private final static String DIR = System.getProperty("test.src", "."); + private static final char[] PASSWORD = "passphrase".toCharArray(); + private static final String KEYSTORE = "truststore.p12"; + private static final String CERT = DIR + "/trusted.pem"; + private static final String ALIAS = "my trustedcert"; + private static final String ALIAS2 = "my trustedcert with attributes"; + + public static void main(String[] args) throws Exception { + + new File(KEYSTORE).delete(); + + try { + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(null, null); + + Certificate cert = loadCertificate(CERT); + Set attributes = new HashSet<>(); + attributes.add(new PKCS12Attribute("1.3.5.7.9", "that's odd")); + attributes.add(new PKCS12Attribute("2.4.6.8.10", "that's even")); + + // Set trusted certificate entry + keystore.setEntry(ALIAS, + new KeyStore.TrustedCertificateEntry(cert), null); + + // Set trusted certificate entry with attributes + keystore.setEntry(ALIAS2, + new KeyStore.TrustedCertificateEntry(cert, attributes), null); + + System.out.println("Storing keystore to: " + KEYSTORE); + keystore.store(new FileOutputStream(KEYSTORE), PASSWORD); + + System.out.println("Loading keystore from: " + KEYSTORE); + keystore.load(new FileInputStream(KEYSTORE), PASSWORD); + System.out.println("Loaded keystore with " + keystore.size() + + " entries"); + + KeyStore.Entry entry = keystore.getEntry(ALIAS, null); + if (entry instanceof KeyStore.TrustedCertificateEntry) { + System.out.println("Retrieved trusted certificate entry: " + + entry); + } else { + throw new Exception("Not a trusted certificate entry"); + } + System.out.println(); + + entry = keystore.getEntry(ALIAS2, null); + if (entry instanceof KeyStore.TrustedCertificateEntry) { + KeyStore.TrustedCertificateEntry trustedEntry = + (KeyStore.TrustedCertificateEntry) entry; + Set entryAttributes = + trustedEntry.getAttributes(); + + if (entryAttributes.containsAll(attributes)) { + System.out.println("Retrieved trusted certificate entry " + + "with attributes: " + entry); + } else { + throw new Exception("Failed to retrieve entry attributes"); + } + } else { + throw new Exception("Not a trusted certificate entry"); + } + + } finally { + new File(KEYSTORE).delete(); + } + } + + 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/pkcs12/trusted.pem b/jdk/test/sun/security/pkcs12/trusted.pem new file mode 100644 index 00000000000..32e7b84f357 --- /dev/null +++ b/jdk/test/sun/security/pkcs12/trusted.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIF5DCCBMygAwIBAgIQGVCD3zqdD1ZMZZ/zLAPnQzANBgkqhkiG9w0BAQUFADCBvDELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29t +L3JwYSAoYykxMDE2MDQGA1UEAxMtVmVyaVNpZ24gQ2xhc3MgMyBJbnRlcm5hdGlvbmFsIFNlcnZl +ciBDQSAtIEczMB4XDTEyMDcxMDAwMDAwMFoXDTEzMDczMTIzNTk1OVowgbgxCzAJBgNVBAYTAlVT +MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQHFA5SZWR3b29kIFNob3JlczEbMBkGA1UEChQS +T3JhY2xlIENvcnBvcmF0aW9uMRIwEAYDVQQLFAlHbG9iYWwgSVQxMzAxBgNVBAsUKlRlcm1zIG9m +IHVzZSBhdCB3d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNTEVMBMGA1UEAxQMKi5vcmFjbGUuY29t +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz/dOCGrWzPj62q0ZkF59Oj9Fli4wHAuX +U4/S0yBXF8j6K7TKWFTQkGZt3+08KUhmLm1CE1DbbyRJT292YNXYXunNaKdABob8kaBO/NESUOEJ +0SZh7fd0xCSJAAPiwOMrM5jLeb/dEpU6nP74Afrhu5ffvKdcvTRGguj9H2oVsisTK8Z1HsiiwcJG +JXcrjvdCZoPU4FHvK03XZPAqPHKNSaJOrux6kRIWYjQMlmL+qDOb0nNHa6gBdi+VqqJHJHeAM677 +dcUd0jn2m2OWtUnrM3MJZQof7/z27RTdX5J8np0ChkUgm63biDgRZO7uZP0DARQ0I6lZMlrarT8/ +sct3twIDAQABo4IB4jCCAd4wFwYDVR0RBBAwDoIMKi5vcmFjbGUuY29tMAkGA1UdEwQCMAAwCwYD +VR0PBAQDAgWgMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHFwMwKjAoBggrBgEFBQcCARYcaHR0cHM6 +Ly93d3cudmVyaXNpZ24uY29tL3JwYTAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwbgYI +KwYBBQUHAQwEYjBgoV6gXDBaMFgwVhYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUS2u5KJYGDLvQ +UjibKaxLB4shBRgwJhYkaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nbzEuZ2lmMHIGCCsG +AQUFBwEBBGYwZDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AudmVyaXNpZ24uY29tMDwGCCsGAQUF +BzAChjBodHRwOi8vc3ZyaW50bC1nMy1haWEudmVyaXNpZ24uY29tL1NWUkludGxHMy5jZXIwQQYD +VR0fBDowODA2oDSgMoYwaHR0cDovL3N2cmludGwtZzMtY3JsLnZlcmlzaWduLmNvbS9TVlJJbnRs +RzMuY3JsMB8GA1UdIwQYMBaAFNebfNgioBX33a1fzimbWMO8RgC1MA0GCSqGSIb3DQEBBQUAA4IB +AQAITRBlEo+qXLwCL53Db2BGnhDgnSomjne8aCmU7Yt4Kp91tzJdhNuaC/wwDuzD2dPJqzemae3s +wKiOXrmDQZDj9NNTdkrXHnCvDR4TpOynWe3zBa0bwKnV2cIRKcv482yV53u0kALyFZbagYPwOOz3 +YJA/2SqdcDn9Ztc/ABQ1SkyXyA5j4LJdf2g7BtYrFxjy0RG6We2iM781WSB/9MCNKyHgiwd3KpLf +urdSKLzy1elNAyt1P3UHwBIIvZ6sJIr/eeELc54Lxt6PtQCXx8qwxYTYXWPXbLgKBHdebgrmAbPK +TfD69wysvjk6vwSHjmvaqB4R4WRcgkuT+1gxx+ve +-----END CERTIFICATE----- diff --git a/jdk/test/sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.sh b/jdk/test/sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.sh index b09d1564b7f..70d42151373 100644 --- a/jdk/test/sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.sh +++ b/jdk/test/sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.sh @@ -41,6 +41,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -65,12 +69,14 @@ esac # compile the test program cd ${TESTSRC}${FILESEP} rm GrantAllPermToExtWhenNoPolicy.class -${TESTJAVA}${FILESEP}bin${FILESEP}javac -d ${TESTSRC}${FILESEP} ${TESTSRC}${FILESEP}SomeExtensionClass.java -${TESTJAVA}${FILESEP}bin${FILESEP}javac -d ${TESTSRC}${FILESEP} ${TESTSRC}${FILESEP}GrantAllPermToExtWhenNoPolicy.java +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -d ${TESTSRC}${FILESEP} ${TESTSRC}${FILESEP}SomeExtensionClass.java +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -d ${TESTSRC}${FILESEP} ${TESTSRC}${FILESEP}GrantAllPermToExtWhenNoPolicy.java # create the extension JAR file cd ${TESTCLASSES} -${TESTJAVA}${FILESEP}bin${FILESEP}jar cvf SomeExt.jar SomeExtensionClass*.class +${COMPILEJAVA}${FILESEP}bin${FILESEP}jar cvf SomeExt.jar SomeExtensionClass*.class rm SomeExtensionClass.class # move the extension JAR file to the extension directory diff --git a/jdk/test/sun/security/provider/PolicyFile/getinstance/getinstance.sh b/jdk/test/sun/security/provider/PolicyFile/getinstance/getinstance.sh index 893bbb65bc5..5775eab80b1 100644 --- a/jdk/test/sun/security/provider/PolicyFile/getinstance/getinstance.sh +++ b/jdk/test/sun/security/provider/PolicyFile/getinstance/getinstance.sh @@ -44,6 +44,10 @@ if [ "${TESTJAVA}" = "" ] ; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + # set platform-dependent variables OS=`uname -s` case "$OS" in @@ -81,15 +85,15 @@ if [ ! -d ${TESTCLASSES}${FS}app ]; then fi cd ${TESTSRC}${FS} -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS}boot \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS}boot \ ${TESTSRC}${FS}NoArgPermission.java -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS}boot \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS}boot \ ${TESTSRC}${FS}OneArgPermission.java -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS}boot \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS}boot \ ${TESTSRC}${FS}TwoArgPermission.java -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS}boot \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS}boot \ ${TESTSRC}${FS}TwoArgNullActionsPermission.java -${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES}${FS}app \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${TESTCLASSES}${FS}app \ ${TESTSRC}${FS}GetInstance.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \ diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/EngineArgs/DebugReportsOneExtraByte.sh b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/EngineArgs/DebugReportsOneExtraByte.sh index f29f6cedd94..9b48bee7f3b 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/EngineArgs/DebugReportsOneExtraByte.sh +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/EngineArgs/DebugReportsOneExtraByte.sh @@ -51,7 +51,8 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}DebugReportsOneExtraByte.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}${FS}DebugReportsOneExtraByte.java STRING='main, WRITE: TLSv1 Application Data, length = 8' diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh index 60a38468be5..eff4930de4a 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh @@ -35,6 +35,10 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then TESTSRC="." @@ -63,12 +67,12 @@ set -ex # # Compile the tests, package into their respective jars # -${TESTJAVA}${FILESEP}bin${FILESEP}javac -d . \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ ${TESTSRC}${FILESEP}NotifyHandshakeTest.java \ ${TESTSRC}${FILESEP}NotifyHandshakeTestHeyYou.java -${TESTJAVA}${FILESEP}bin${FILESEP}jar -cvf com.jar \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}jar ${TESTTOOLVMOPTS} -cvf com.jar \ com${FILESEP}NotifyHandshakeTest*.class -${TESTJAVA}${FILESEP}bin${FILESEP}jar -cvf edu.jar \ +${COMPILEJAVA}${FILESEP}bin${FILESEP}jar ${TESTTOOLVMOPTS} -cvf edu.jar \ edu${FILESEP}NotifyHandshakeTestHeyYou.class # diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java index a521db2911d..26c4f400b83 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.java @@ -153,7 +153,7 @@ public class PostThruProxy { /* * setup up a proxy */ - setupProxy(); + SocketAddress pAddr = setupProxy(); /* * we want to avoid URLspoofCheck failures in cases where the cert @@ -163,7 +163,8 @@ public class PostThruProxy { new NameVerifier()); URL url = new URL("https://" + hostname+ ":" + serverPort); - HttpsURLConnection https = (HttpsURLConnection)url.openConnection(); + Proxy p = new Proxy(Proxy.Type.HTTP, pAddr); + HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p); https.setDoOutput(true); https.setRequestMethod("POST"); PrintStream ps = null; @@ -200,14 +201,12 @@ public class PostThruProxy { } } - static void setupProxy() throws IOException { + static SocketAddress setupProxy() throws IOException { ProxyTunnelServer pserver = new ProxyTunnelServer(); // disable proxy authentication pserver.needUserAuth(false); pserver.start(); - System.setProperty("https.proxyHost", "localhost"); - System.setProperty("https.proxyPort", String.valueOf( - pserver.getPort())); + return new InetSocketAddress("localhost", pserver.getPort()); } } diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh index 85e9c22c4af..4cdc5d4d1b7 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh @@ -50,7 +50,9 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}OriginServer.java \ - ${TESTSRC}${FS}ProxyTunnelServer.java ${TESTSRC}${FS}PostThruProxy.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + ${TESTSRC}${FS}OriginServer.java \ + ${TESTSRC}${FS}ProxyTunnelServer.java \ + ${TESTSRC}${FS}PostThruProxy.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxy ${HOSTNAME} ${TESTSRC} exit diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java index a010be0630c..11fe859223c 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.java @@ -152,7 +152,7 @@ public class PostThruProxyWithAuth { /* * setup up a proxy */ - setupProxy(); + SocketAddress pAddr = setupProxy(); /* * we want to avoid URLspoofCheck failures in cases where the cert @@ -162,7 +162,8 @@ public class PostThruProxyWithAuth { new NameVerifier()); URL url = new URL("https://" + hostname + ":" + serverPort); - HttpsURLConnection https = (HttpsURLConnection)url.openConnection(); + Proxy p = new Proxy(Proxy.Type.HTTP, pAddr); + HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p); https.setDoOutput(true); https.setRequestMethod("POST"); PrintStream ps = null; @@ -195,7 +196,7 @@ public class PostThruProxyWithAuth { } } - static void setupProxy() throws IOException { + static SocketAddress setupProxy() throws IOException { ProxyTunnelServer pserver = new ProxyTunnelServer(); /* @@ -209,9 +210,8 @@ public class PostThruProxyWithAuth { pserver.setUserAuth("Test", "test123"); pserver.start(); - System.setProperty("https.proxyHost", "localhost"); - System.setProperty("https.proxyPort", String.valueOf( - pserver.getPort())); + + return new InetSocketAddress("localhost", pserver.getPort()); } public static class TestAuthenticator extends Authenticator { @@ -220,6 +220,4 @@ public class PostThruProxyWithAuth { "test123".toCharArray()); } } - - } diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh index 96c0642480b..de7b039488c 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh @@ -50,7 +50,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}OriginServer.java \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}OriginServer.java \ ${TESTSRC}${FS}ProxyTunnelServer.java \ ${TESTSRC}${FS}PostThruProxyWithAuth.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC} diff --git a/jdk/test/sun/security/tools/keytool/autotest.sh b/jdk/test/sun/security/tools/keytool/autotest.sh index 56836d107c3..9c797dd21e5 100644 --- a/jdk/test/sun/security/tools/keytool/autotest.sh +++ b/jdk/test/sun/security/tools/keytool/autotest.sh @@ -40,6 +40,9 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi find_one() { for TARGET_FILE in $@; do @@ -82,7 +85,7 @@ if [ "$LIBNAME" = "" ]; then exit 1 fi -${TESTJAVA}${FS}bin${FS}javac -d . -XDignore.symbol.file \ +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file \ ${TESTSRC}${FS}KeyToolTest.java || exit 10 NSS=${TESTSRC}${FS}..${FS}..${FS}pkcs11${FS}nss diff --git a/jdk/test/sun/security/tools/keytool/printssl.sh b/jdk/test/sun/security/tools/keytool/printssl.sh index 46de2609b0b..36ba9d09437 100644 --- a/jdk/test/sun/security/tools/keytool/printssl.sh +++ b/jdk/test/sun/security/tools/keytool/printssl.sh @@ -33,6 +33,9 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi # set platform-dependent variables OS=`uname -s` @@ -52,7 +55,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}PrintSSL.java || exit 10 +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}PrintSSL.java || exit 10 ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dtest.src=$TESTSRC PrintSSL | ( read PORT; ${TESTJAVA}${FS}bin${FS}keytool -printcert -sslserver localhost:$PORT ) status=$? diff --git a/jdk/test/sun/security/tools/keytool/readjar.sh b/jdk/test/sun/security/tools/keytool/readjar.sh index f0a51216b31..037a90818c8 100644 --- a/jdk/test/sun/security/tools/keytool/readjar.sh +++ b/jdk/test/sun/security/tools/keytool/readjar.sh @@ -29,6 +29,7 @@ if [ "${TESTJAVA}" = "" ] ; then JAVAC_CMD=`which javac` TESTJAVA=`dirname $JAVAC_CMD`/.. + COMPILEJAVA=${TESTJAVA} fi # set platform-dependent variables @@ -44,13 +45,13 @@ esac KS=readjar.jks rm $KS -$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS \ +$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepass changeit -keypass changeit -keystore $KS \ -alias x -dname CN=X -genkeypair -$TESTJAVA${FS}bin${FS}jar cvf readjar.jar $KS -$TESTJAVA${FS}bin${FS}jarsigner -storepass changeit -keystore $KS readjar.jar x +$COMPILEJAVA${FS}bin${FS}jar ${TESTTOOLVMOPTS} cvf readjar.jar $KS +$COMPILEJAVA${FS}bin${FS}jarsigner ${TESTTOOLVMOPTS} -storepass changeit -keystore $KS readjar.jar x -$TESTJAVA${FS}bin${FS}keytool -printcert -jarfile readjar.jar || exit 1 -$TESTJAVA${FS}bin${FS}keytool -printcert -jarfile readjar.jar -rfc || exit 1 +$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -printcert -jarfile readjar.jar || exit 1 +$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -printcert -jarfile readjar.jar -rfc || exit 1 exit 0 diff --git a/jdk/test/sun/security/tools/keytool/standard.sh b/jdk/test/sun/security/tools/keytool/standard.sh index c75a7a49b46..630aa41c46f 100644 --- a/jdk/test/sun/security/tools/keytool/standard.sh +++ b/jdk/test/sun/security/tools/keytool/standard.sh @@ -39,6 +39,7 @@ fi if [ "${TESTJAVA}" = "" ] ; then JAVAC_CMD=`which javac` TESTJAVA=`dirname $JAVAC_CMD`/.. + COMPILEJAVA="${TESTJAVA}" fi # set platform-dependent variables @@ -56,7 +57,7 @@ case "$OS" in ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dfile KeyToolTest status=$? diff --git a/jdk/test/sun/security/tools/policytool/UpdatePermissions.html b/jdk/test/sun/security/tools/policytool/UpdatePermissions.html index 00ba1dc76e9..5ae3cbcc421 100644 --- a/jdk/test/sun/security/tools/policytool/UpdatePermissions.html +++ b/jdk/test/sun/security/tools/policytool/UpdatePermissions.html @@ -42,7 +42,7 @@ and click "OK".

    setSecurityManager, shutdownHooks, stopThread
    - SecurityPermission: printIdentity

    + SecurityPermission: createAccessControlContext

    In the confirmation dialog pop-up, click "OK".

    diff --git a/jdk/test/sun/security/util/Oid/S11N.sh b/jdk/test/sun/security/util/Oid/S11N.sh index 488c8959094..a19af17be5f 100644 --- a/jdk/test/sun/security/util/Oid/S11N.sh +++ b/jdk/test/sun/security/util/Oid/S11N.sh @@ -39,6 +39,9 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi # set platform-dependent variables PF="" @@ -103,7 +106,7 @@ echo "===================================================" # the test code -${TESTJAVA}${FS}bin${FS}javac -target 1.4 -source 1.4 \ +${COMPILEJAVA}${FS}bin${FS}javac -target 1.4 -source 1.4 \ -d . ${TESTSRC}${FS}SerialTest.java || exit 10 # You can set ALT_JAVA_RE_JDK to another location that contains the diff --git a/jdk/test/sun/security/validator/certreplace.sh b/jdk/test/sun/security/validator/certreplace.sh index b45a70edaa8..78f821bf153 100644 --- a/jdk/test/sun/security/validator/certreplace.sh +++ b/jdk/test/sun/security/validator/certreplace.sh @@ -33,6 +33,7 @@ fi if [ "${TESTJAVA}" = "" ] ; then JAVAC_CMD=`which javac` TESTJAVA=`dirname $JAVAC_CMD`/.. + COMPILEJAVA="${TESTJAVA}" fi # set platform-dependent variables @@ -48,7 +49,7 @@ esac KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit \ -keypass changeit -keystore certreplace.jks" -JAVAC=$TESTJAVA${FS}bin${FS}javac +JAVAC=$COMPILEJAVA${FS}bin${FS}javac JAVA=$TESTJAVA${FS}bin${FS}java rm -rf certreplace.jks 2> /dev/null @@ -81,5 +82,5 @@ $KT -delete -alias user # 5. Build and run test -$JAVAC -d . ${TESTSRC}${FS}CertReplace.java +$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java $JAVA ${TESTVMOPTS} CertReplace certreplace.jks certreplace.certs diff --git a/jdk/test/sun/security/validator/samedn.sh b/jdk/test/sun/security/validator/samedn.sh index 5d9b0455713..0e3e8370800 100644 --- a/jdk/test/sun/security/validator/samedn.sh +++ b/jdk/test/sun/security/validator/samedn.sh @@ -33,6 +33,7 @@ fi if [ "${TESTJAVA}" = "" ] ; then JAVAC_CMD=`which javac` TESTJAVA=`dirname $JAVAC_CMD`/.. + COMPILEJAVA="${TESTJAVA}" fi # set platform-dependent variables @@ -48,7 +49,7 @@ esac KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit \ -keypass changeit -keystore samedn.jks" -JAVAC=$TESTJAVA${FS}bin${FS}javac +JAVAC=$COMPILEJAVA${FS}bin${FS}javac JAVA=$TESTJAVA${FS}bin${FS}java rm -rf samedn.jks 2> /dev/null @@ -77,6 +78,6 @@ $KT -delete -alias user # 5. Build and run test. Make sure the CA certs are ignored for validity check. # Check both, one of them might be dropped out of map in old codes. -$JAVAC -d . ${TESTSRC}${FS}CertReplace.java +$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java $JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn1.certs || exit 1 $JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn2.certs || exit 2 diff --git a/jdk/test/sun/security/x509/URIName/Parse.java b/jdk/test/sun/security/x509/URIName/Parse.java index d99aa30ac1f..c53450840a6 100644 --- a/jdk/test/sun/security/x509/URIName/Parse.java +++ b/jdk/test/sun/security/x509/URIName/Parse.java @@ -1,5 +1,5 @@ /* - * 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 @@ -23,11 +23,12 @@ /* * @test - * @bug 6500133 - * @summary CRL Distribution Point URIs with spaces or backslashes should be - * parseable + * @bug 8005389 + * @summary CRL Distribution Point URIs with spaces or backslashes should + * not be parseable */ import java.io.ByteArrayInputStream; +import java.io.IOException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import sun.security.util.DerValue; @@ -90,27 +91,45 @@ public class Parse { } public static void main(String[] args) throws Exception { - /* Parse a CRLDistributionPointsExtension URI with a space. */ - CRLDistributionPointsExtensionTest(certWithSpaceInCDPStr); - System.out.println("Parsed CRLDistributionPointsExtension uri with " - + "a space."); + /* Try to parse a CRLDistributionPointsExtension URI with a space. */ + try { + CRLDistributionPointsExtensionTest(certWithSpaceInCDPStr); + throw new RuntimeException("Illegally parsed a " + + "CRLDistributionPointsExtension uri with a space."); + } catch (IOException e) { + System.out.println("Caught the correct exception."); - /* Parse a CRLDistributionPointsExtension URI with backslashes. */ - CRLDistributionPointsExtensionTest(certWithBackslashesInCDPStr); - System.out.println("Parsed CRLDistributionPointsExtension uri with " - + "backslashes."); + } - /* Constructor a URIName from a uri with a space. */ + /* Try to parse a CRLDistributionPointsExtension URI with backslashes. */ + try { + CRLDistributionPointsExtensionTest(certWithBackslashesInCDPStr); + throw new RuntimeException("Illegally parsed a " + + "CRLDistributionPointsExtension uri with a backslashes."); + } catch (IOException e) { + System.out.println("Caught the correct exception."); + } + + /* Try to construct a URIName from a uri with a space. */ String uriWithSpace = "file://crl file.crl"; - URIName name = new URIName(uriWithSpace); - System.out.println("URI re-encoded from " + uriWithSpace - + " to " + name.getName()); + URIName name; + try { + name = new URIName(uriWithSpace); + throw new RuntimeException("Illegally created a URIName " + + "from a uri with a space."); + } catch (IOException e) { + System.out.println("Caught the correct exception."); + } - /* Construct a URIName from a uri with backslashes. */ + /* Try to construct a URIName from a uri with backslashes. */ String uriWithBackslashes = "file://\\\\CRL\\crl_file.crl"; - name = new URIName(uriWithBackslashes); - System.out.println("URI re-encoded from " + uriWithBackslashes - + " to " + name.getName()); + try { + name = new URIName(uriWithBackslashes); + throw new RuntimeException("Illegally created a URIName " + + "from a uri with backslashes."); + } catch (IOException e) { + System.out.println("Caught the correct exception."); + } System.out.println("Tests passed."); } diff --git a/jdk/test/sun/security/x509/X509CRLImpl/Verify.java b/jdk/test/sun/security/x509/X509CRLImpl/Verify.java index f55f1bffb5e..0c1b30d74f1 100644 --- a/jdk/test/sun/security/x509/X509CRLImpl/Verify.java +++ b/jdk/test/sun/security/x509/X509CRLImpl/Verify.java @@ -95,7 +95,7 @@ public class Verify { * Should fail with NoSuchAlgorithmException. */ try { - verifyCRL(crlIssuerCertPubKey, "SunPCSC"); + verifyCRL(crlIssuerCertPubKey, "SunJCE"); throw new RuntimeException("Didn't catch the exception properly"); } catch (NoSuchAlgorithmException e) { System.out.println("Caught the correct exception."); @@ -148,6 +148,10 @@ public class Verify { throws CRLException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { Provider provider = Security.getProvider(providerName); + if (provider == null) { + throw new RuntimeException("Provider " + providerName + + " not found."); + } crl.verify(key, provider); } } diff --git a/jdk/test/sun/security/x509/X509CertImpl/Verify.java b/jdk/test/sun/security/x509/X509CertImpl/Verify.java index 09c1e0e1b97..89dcbb9f1b9 100644 --- a/jdk/test/sun/security/x509/X509CertImpl/Verify.java +++ b/jdk/test/sun/security/x509/X509CertImpl/Verify.java @@ -86,7 +86,7 @@ public class Verify { * Should fail with NoSuchAlgorithmException. */ try { - verifyCert(selfSignedCertPubKey, "SunPCSC"); + verifyCert(selfSignedCertPubKey, "SunJCE"); throw new RuntimeException("Didn't catch the exception properly"); } catch (NoSuchAlgorithmException e) { System.out.println("Caught the correct exception."); @@ -134,6 +134,10 @@ public class Verify { throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { Provider provider = Security.getProvider(providerName); + if (provider == null) { + throw new RuntimeException("Provider " + providerName + + " not found."); + } cert.verify(key, provider); } } diff --git a/jdk/test/sun/text/resources/LocaleData b/jdk/test/sun/text/resources/LocaleData index 87b9d44cb27..51145049ec9 100644 --- a/jdk/test/sun/text/resources/LocaleData +++ b/jdk/test/sun/text/resources/LocaleData @@ -7661,5 +7661,1139 @@ FormatData/zh/DayNarrows/6=\u516d # bug 7195759 CurrencyNames//ZMW=ZMW +# rfe 8004489, 8006509 +FormatData//calendarname.buddhist=Buddhist Calendar +FormatData//calendarname.gregorian=Gregorian Calendar +FormatData//calendarname.gregory=Gregorian Calendar +FormatData//calendarname.islamic-civil=Islamic-Civil Calendar +FormatData//calendarname.islamic=Islamic Calendar +FormatData//calendarname.islamicc=Islamic-Civil Calendar +FormatData//calendarname.japanese=Japanese Calendar +FormatData//calendarname.roc=Minguo Calendar +FormatData//field.dayperiod=Dayperiod +FormatData//field.era=Era +FormatData//field.hour=Hour +FormatData//field.minute=Minute +FormatData//field.month=Month +FormatData//field.second=Second +FormatData//field.week=Week +FormatData//field.weekday=Day of the Week +FormatData//field.year=Year +FormatData//field.zone=Zone +FormatData//islamic.Eras/0= +FormatData//islamic.Eras/1=AH +FormatData//islamic.MonthNames/0=Muharram +FormatData//islamic.MonthNames/1=Safar +FormatData//islamic.MonthNames/2=Rabi\u02bb I +FormatData//islamic.MonthNames/3=Rabi\u02bb II +FormatData//islamic.MonthNames/4=Jumada I +FormatData//islamic.MonthNames/5=Jumada II +FormatData//islamic.MonthNames/6=Rajab +FormatData//islamic.MonthNames/7=Sha\u02bbban +FormatData//islamic.MonthNames/8=Ramadan +FormatData//islamic.MonthNames/9=Shawwal +FormatData//islamic.MonthNames/10=Dhu\u02bbl-Qi\u02bbdah +FormatData//islamic.MonthNames/11=Dhu\u02bbl-Hijjah +FormatData//islamic.MonthNames/12= +FormatData//islamic.MonthAbbreviations/0=Muh. +FormatData//islamic.MonthAbbreviations/1=Saf. +FormatData//islamic.MonthAbbreviations/2=Rab. I +FormatData//islamic.MonthAbbreviations/3=Rab. II +FormatData//islamic.MonthAbbreviations/4=Jum. I +FormatData//islamic.MonthAbbreviations/5=Jum. II +FormatData//islamic.MonthAbbreviations/6=Raj. +FormatData//islamic.MonthAbbreviations/7=Sha. +FormatData//islamic.MonthAbbreviations/8=Ram. +FormatData//islamic.MonthAbbreviations/9=Shaw. +FormatData//islamic.MonthAbbreviations/10=Dhu\u02bbl-Q. +FormatData//islamic.MonthAbbreviations/11=Dhu\u02bbl-H. +FormatData//islamic.MonthAbbreviations/12= +FormatData//islamic.DatePatterns/0=EEEE, MMMM d, y GGGG +FormatData//islamic.DatePatterns/1=MMMM d, y GGGG +FormatData//islamic.DatePatterns/2=MMM d, y GGGG +FormatData//islamic.DatePatterns/3=M/d/yy GGGG +FormatData//roc.Eras/0=Before R.O.C. +FormatData//roc.Eras/1=R.O.C. +FormatData//roc.DatePatterns/0=EEEE, GGGG y MMMM dd +FormatData//roc.DatePatterns/1=GGGG y MMMM d +FormatData//roc.DatePatterns/2=GGGG y MMM d +FormatData//roc.DatePatterns/3=G yyy-MM-dd +FormatData/ar/calendarname.buddhist=\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0628\u0648\u0630\u064a +FormatData/ar/calendarname.gregorian=\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0645\u064a\u0644\u0627\u062f\u064a +FormatData/ar/calendarname.gregory=\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0645\u064a\u0644\u0627\u062f\u064a +FormatData/ar/calendarname.islamic-civil=\u062a\u0642\u0648\u064a\u0645 \u0627\u0633\u0644\u0627\u0645\u064a \u0645\u062f\u0646\u064a +FormatData/ar/calendarname.islamic=\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u0647\u062c\u0631\u064a +FormatData/ar/calendarname.islamicc=\u062a\u0642\u0648\u064a\u0645 \u0627\u0633\u0644\u0627\u0645\u064a \u0645\u062f\u0646\u064a +FormatData/ar/calendarname.japanese=\u0627\u0644\u062a\u0642\u0648\u064a\u0645 \u0627\u0644\u064a\u0627\u0628\u0627\u0646\u064a +FormatData/ar/calendarname.roc=\u062a\u0642\u0648\u064a\u0645 \u0645\u064a\u0646\u062c\u0648 +FormatData/ar/field.dayperiod=\u0635/\u0645 +FormatData/ar/field.era=\u0627\u0644\u0639\u0635\u0631 +FormatData/ar/field.hour=\u0627\u0644\u0633\u0627\u0639\u0627\u062a +FormatData/ar/field.minute=\u0627\u0644\u062f\u0642\u0627\u0626\u0642 +FormatData/ar/field.month=\u0627\u0644\u0634\u0647\u0631 +FormatData/ar/field.second=\u0627\u0644\u062b\u0648\u0627\u0646\u064a +FormatData/ar/field.week=\u0627\u0644\u0623\u0633\u0628\u0648\u0639 +FormatData/ar/field.weekday=\u0627\u0644\u064a\u0648\u0645 +FormatData/ar/field.year=\u0627\u0644\u0633\u0646\u0629 +FormatData/ar/field.zone=\u0627\u0644\u062a\u0648\u0642\u064a\u062a +FormatData/ar/islamic.MonthNames/0=\u0645\u062d\u0631\u0645 +FormatData/ar/islamic.MonthNames/1=\u0635\u0641\u0631 +FormatData/ar/islamic.MonthNames/2=\u0631\u0628\u064a\u0639 \u0627\u0644\u0623\u0648\u0644 +FormatData/ar/islamic.MonthNames/3=\u0631\u0628\u064a\u0639 \u0627\u0644\u0622\u062e\u0631 +FormatData/ar/islamic.MonthNames/4=\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0623\u0648\u0644\u0649 +FormatData/ar/islamic.MonthNames/5=\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0622\u062e\u0631\u0629 +FormatData/ar/islamic.MonthNames/6=\u0631\u062c\u0628 +FormatData/ar/islamic.MonthNames/7=\u0634\u0639\u0628\u0627\u0646 +FormatData/ar/islamic.MonthNames/8=\u0631\u0645\u0636\u0627\u0646 +FormatData/ar/islamic.MonthNames/9=\u0634\u0648\u0627\u0644 +FormatData/ar/islamic.MonthNames/10=\u0630\u0648 \u0627\u0644\u0642\u0639\u062f\u0629 +FormatData/ar/islamic.MonthNames/11=\u0630\u0648 \u0627\u0644\u062d\u062c\u0629 +FormatData/ar/islamic.MonthNames/12= +FormatData/ar/islamic.MonthAbbreviations/0=\u0645\u062d\u0631\u0645 +FormatData/ar/islamic.MonthAbbreviations/1=\u0635\u0641\u0631 +FormatData/ar/islamic.MonthAbbreviations/2=\u0631\u0628\u064a\u0639 \u0627\u0644\u0623\u0648\u0644 +FormatData/ar/islamic.MonthAbbreviations/3=\u0631\u0628\u064a\u0639 \u0627\u0644\u0622\u062e\u0631 +FormatData/ar/islamic.MonthAbbreviations/4=\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0623\u0648\u0644\u0649 +FormatData/ar/islamic.MonthAbbreviations/5=\u062c\u0645\u0627\u062f\u0649 \u0627\u0644\u0622\u062e\u0631\u0629 +FormatData/ar/islamic.MonthAbbreviations/6=\u0631\u062c\u0628 +FormatData/ar/islamic.MonthAbbreviations/7=\u0634\u0639\u0628\u0627\u0646 +FormatData/ar/islamic.MonthAbbreviations/8=\u0631\u0645\u0636\u0627\u0646 +FormatData/ar/islamic.MonthAbbreviations/9=\u0634\u0648\u0627\u0644 +FormatData/ar/islamic.MonthAbbreviations/10=\u0630\u0648 \u0627\u0644\u0642\u0639\u062f\u0629 +FormatData/ar/islamic.MonthAbbreviations/11=\u0630\u0648 \u0627\u0644\u062d\u062c\u0629 +FormatData/ar/islamic.MonthAbbreviations/12= +FormatData/ar/islamic.Eras/0= +FormatData/ar/islamic.Eras/1=\u0647\u0640 +FormatData//islamic.DatePatterns/0=EEEE, MMMM d, y GGGG +FormatData//islamic.DatePatterns/1=MMMM d, y GGGG +FormatData//islamic.DatePatterns/2=MMM d, y GGGG +FormatData//islamic.DatePatterns/3=M/d/yy GGGG +FormatData/ar/roc.DatePatterns/0=EEEE\u060c d MMMM\u060c y GGGG +FormatData/ar/roc.DatePatterns/1=d MMMM\u060c y GGGG +FormatData/ar/roc.DatePatterns/2=dd\u200f/MM\u200f/y GGGG +FormatData/ar/roc.DatePatterns/3=d\u200f/M\u200f/y GGGG +FormatData/be/calendarname.buddhist=\u0431\u0443\u0434\u044b\u0441\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.gregorian=\u0433\u0440\u044d\u0433\u0430\u0440\u044b\u044f\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.gregory=\u0433\u0440\u044d\u0433\u0430\u0440\u044b\u044f\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.islamic-civil=\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u0441\u0432\u0435\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.islamic=\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.islamicc=\u043c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u043a\u0456 \u0441\u0432\u0435\u0446\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/calendarname.japanese=\u044f\u043f\u043e\u043d\u0441\u043a\u0456 \u043a\u0430\u043b\u044f\u043d\u0434\u0430\u0440 +FormatData/be/field.era=\u044d\u0440\u0430 +FormatData/be/field.hour=\u0433\u0430\u0434\u0437\u0456\u043d\u0430 +FormatData/be/field.minute=\u0445\u0432\u0456\u043b\u0456\u043d\u0430 +FormatData/be/field.month=\u043c\u0435\u0441\u044f\u0446 +FormatData/be/field.second=\u0441\u0435\u043a\u0443\u043d\u0434\u0430 +FormatData/be/field.week=\u0442\u044b\u0434\u0437\u0435\u043d\u044c +FormatData/be/field.weekday=\u0434\u0437\u0435\u043d\u044c \u0442\u044b\u0434\u043d\u044f +FormatData/be/field.year=\u0433\u043e\u0434 +FormatData/bg/calendarname.buddhist=\u0411\u0443\u0434\u0438\u0441\u0442\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.gregorian=\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.gregory=\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.islamic-civil=\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u0435\u043d \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.islamic=\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.islamicc=\u0418\u0441\u043b\u044f\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u0435\u043d \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.japanese=\u042f\u043f\u043e\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/bg/calendarname.roc=\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u043d\u0430 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0430 \u041a\u0438\u0442\u0430\u0439 +FormatData/bg/field.dayperiod=\u0434\u0435\u043d +FormatData/bg/field.era=\u0435\u0440\u0430 +FormatData/bg/field.hour=\u0447\u0430\u0441 +FormatData/bg/field.minute=\u043c\u0438\u043d\u0443\u0442\u0430 +FormatData/bg/field.month=\u043c\u0435\u0441\u0435\u0446 +FormatData/bg/field.second=\u0441\u0435\u043a\u0443\u043d\u0434\u0430 +FormatData/bg/field.week=\u0441\u0435\u0434\u043c\u0438\u0446\u0430 +FormatData/bg/field.weekday=\u0414\u0435\u043d \u043e\u0442 \u0441\u0435\u0434\u043c\u0438\u0446\u0430\u0442\u0430 +FormatData/bg/field.year=\u0433\u043e\u0434\u0438\u043d\u0430 +FormatData/bg/field.zone=\u0437\u043e\u043d\u0430 +FormatData/bg/islamic.MonthNames/0=\u043c\u0443\u0445\u0430\u0440\u0430\u043c +FormatData/bg/islamic.MonthNames/1=\u0441\u0430\u0444\u0430\u0440 +FormatData/bg/islamic.MonthNames/2=\u0440\u0430\u0431\u0438-1 +FormatData/bg/islamic.MonthNames/3=\u0440\u0430\u0431\u0438-2 +FormatData/bg/islamic.MonthNames/4=\u0434\u0436\u0443\u043c\u0430\u0434\u0430-1 +FormatData/bg/islamic.MonthNames/5=\u0434\u0436\u0443\u043c\u0430\u0434\u0430-2 +FormatData/bg/islamic.MonthNames/6=\u0440\u0430\u0434\u0436\u0430\u0431 +FormatData/bg/islamic.MonthNames/7=\u0448\u0430\u0431\u0430\u043d +FormatData/bg/islamic.MonthNames/8=\u0440\u0430\u043c\u0430\u0437\u0430\u043d +FormatData/bg/islamic.MonthNames/9=\u0428\u0430\u0432\u0430\u043b +FormatData/bg/islamic.MonthNames/10=\u0414\u0445\u0443\u043b-\u041a\u0430\u0430\u0434\u0430 +FormatData/bg/islamic.MonthNames/11=\u0414\u0445\u0443\u043b-\u0445\u0438\u0434\u0436\u0430 +FormatData/bg/islamic.MonthNames/12= +FormatData/ca/calendarname.buddhist=calendari budista +FormatData/ca/calendarname.gregorian=calendari gregori\u00e0 +FormatData/ca/calendarname.gregory=calendari gregori\u00e0 +FormatData/ca/calendarname.islamic-civil=calendari civil isl\u00e0mic +FormatData/ca/calendarname.islamic=calendari musulm\u00e0 +FormatData/ca/calendarname.islamicc=calendari civil isl\u00e0mic +FormatData/ca/calendarname.japanese=calendari japon\u00e8s +FormatData/ca/calendarname.roc=calendari de la Rep\u00fablica de Xina +FormatData/ca/field.dayperiod=a.m./p.m. +FormatData/ca/field.era=era +FormatData/ca/field.hour=hora +FormatData/ca/field.minute=minut +FormatData/ca/field.month=mes +FormatData/ca/field.second=segon +FormatData/ca/field.week=setmana +FormatData/ca/field.weekday=dia de la setmana +FormatData/ca/field.year=any +FormatData/ca/field.zone=zona +FormatData/cs/calendarname.buddhist=Buddhistick\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.gregorian=Gregori\u00e1nsk\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.gregory=Gregori\u00e1nsk\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.islamic-civil=Muslimsk\u00fd ob\u010dansk\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.islamic=Muslimsk\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.islamicc=Muslimsk\u00fd ob\u010dansk\u00fd kalend\u00e1\u0159 +FormatData/cs/calendarname.japanese=Japonsk\u00fd kalend\u00e1\u0159 +FormatData/cs/field.dayperiod=AM/PM +FormatData/cs/field.hour=Hodina +FormatData/cs/field.minute=Minuta +FormatData/cs/field.month=M\u011bs\u00edc +FormatData/cs/field.second=Sekunda +FormatData/cs/field.week=T\u00fdden +FormatData/cs/field.weekday=Den v t\u00fddnu +FormatData/cs/field.year=Rok +FormatData/cs/field.zone=\u010casov\u00e9 p\u00e1smo +FormatData/da/calendarname.buddhist=buddhistisk kalender +FormatData/da/calendarname.gregorian=gregoriansk kalender +FormatData/da/calendarname.gregory=gregoriansk kalender +FormatData/da/calendarname.islamic-civil=verdslig islamisk kalender +FormatData/da/calendarname.islamic=islamisk kalender +FormatData/da/calendarname.islamicc=verdslig islamisk kalender +FormatData/da/calendarname.japanese=japansk kalender +FormatData/da/calendarname.roc=kalender for Republikken Kina +FormatData/da/field.dayperiod=dagtid +FormatData/da/field.era=\u00e6ra +FormatData/da/field.hour=time +FormatData/da/field.minute=minut +FormatData/da/field.month=m\u00e5ned +FormatData/da/field.second=sekund +FormatData/da/field.week=uge +FormatData/da/field.weekday=ugedag +FormatData/da/field.year=\u00e5r +FormatData/da/field.zone=tidszone +FormatData/da/roc.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/da/roc.DatePatterns/1=d. MMMM y GGGG +FormatData/da/roc.DatePatterns/2=d. MMM y GGGG +FormatData/da/roc.DatePatterns/3=d/M/y G +FormatData/da/islamic.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/da/islamic.DatePatterns/1=d. MMMM y GGGG +FormatData/da/islamic.DatePatterns/2=d. MMM y GGGG +FormatData/da/islamic.DatePatterns/3=d/M/y GGGG +FormatData/de/calendarname.buddhist=Buddhistischer Kalender +FormatData/de/calendarname.gregorian=Gregorianischer Kalender +FormatData/de/calendarname.gregory=Gregorianischer Kalender +FormatData/de/calendarname.islamic-civil=B\u00fcrgerlicher islamischer Kalender +FormatData/de/calendarname.islamic=Islamischer Kalender +FormatData/de/calendarname.islamicc=B\u00fcrgerlicher islamischer Kalender +FormatData/de/calendarname.japanese=Japanischer Kalender +FormatData/de/calendarname.roc=Kalender der Republik China +FormatData/de/field.dayperiod=Tagesh\u00e4lfte +FormatData/de/field.era=Epoche +FormatData/de/field.hour=Stunde +FormatData/de/field.minute=Minute +FormatData/de/field.month=Monat +FormatData/de/field.second=Sekunde +FormatData/de/field.week=Woche +FormatData/de/field.weekday=Wochentag +FormatData/de/field.year=Jahr +FormatData/de/field.zone=Zone +FormatData/de/roc.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/de/roc.DatePatterns/1=d. MMMM y GGGG +FormatData/de/roc.DatePatterns/2=d. MMM y GGGG +FormatData/de/roc.DatePatterns/3=d.M.y G +FormatData/de/islamic.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/de/islamic.DatePatterns/1=d. MMMM y GGGG +FormatData/de/islamic.DatePatterns/2=d. MMM y GGGG +FormatData/de/islamic.DatePatterns/3=d.M.y GGGG +FormatData/el/calendarname.buddhist=\u0392\u03bf\u03c5\u03b4\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.gregorian=\u0393\u03c1\u03b7\u03b3\u03bf\u03c1\u03b9\u03b1\u03bd\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.gregory=\u0393\u03c1\u03b7\u03b3\u03bf\u03c1\u03b9\u03b1\u03bd\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.islamic-civil=\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b1\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.islamic=\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.islamicc=\u0399\u03c3\u03bb\u03b1\u03bc\u03b9\u03ba\u03cc \u03b1\u03c3\u03c4\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.japanese=\u0399\u03b1\u03c0\u03c9\u03bd\u03b9\u03ba\u03cc \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf +FormatData/el/calendarname.roc=\u0397\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03c4\u03b7\u03c2 \u0394\u03b7\u03bc\u03bf\u03ba\u03c1\u03b1\u03c4\u03af\u03b1\u03c2 \u03c4\u03b7\u03c2 \u039a\u03af\u03bd\u03b1\u03c2 +FormatData/el/field.dayperiod=\u03c0.\u03bc./\u03bc.\u03bc. +FormatData/el/field.era=\u03a0\u03b5\u03c1\u03af\u03bf\u03b4\u03bf\u03c2 +FormatData/el/field.hour=\u038f\u03c1\u03b1 +FormatData/el/field.minute=\u039b\u03b5\u03c0\u03c4\u03cc +FormatData/el/field.month=\u039c\u03ae\u03bd\u03b1\u03c2 +FormatData/el/field.second=\u0394\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03bf +FormatData/el/field.week=\u0395\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b1 +FormatData/el/field.weekday=\u0397\u03bc\u03ad\u03c1\u03b1 \u03b5\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 +FormatData/el/field.year=\u0388\u03c4\u03bf\u03c2 +FormatData/el/field.zone=\u0396\u03ce\u03bd\u03b7 +FormatData/el/roc.DatePatterns/0=EEEE, d MMMM, y GGGG +FormatData/el/roc.DatePatterns/1=d MMMM, y GGGG +FormatData/el/roc.DatePatterns/2=d MMM, y GGGG +FormatData/el/roc.DatePatterns/3=d/M/y GGGG +FormatData/es/calendarname.buddhist=calendario budista +FormatData/es/calendarname.gregorian=calendario gregoriano +FormatData/es/calendarname.gregory=calendario gregoriano +FormatData/es/calendarname.islamic-civil=calendario civil isl\u00e1mico +FormatData/es/calendarname.islamic=calendario isl\u00e1mico +FormatData/es/calendarname.islamicc=calendario civil isl\u00e1mico +FormatData/es/calendarname.japanese=calendario japon\u00e9s +FormatData/es/calendarname.roc=calendario de la Rep\u00fablica de China +FormatData/es/field.dayperiod=periodo del d\u00eda +FormatData/es/field.era=era +FormatData/es/field.hour=hora +FormatData/es/field.minute=minuto +FormatData/es/field.month=mes +FormatData/es/field.second=segundo +FormatData/es/field.week=semana +FormatData/es/field.weekday=d\u00eda de la semana +FormatData/es/field.year=a\u00f1o +FormatData/es/field.zone=zona +FormatData/es/roc.DatePatterns/0=EEEE, d 'de' MMMM 'de' y GGGG +FormatData/es/roc.DatePatterns/1=d 'de' MMMM 'de' y GGGG +FormatData/es/roc.DatePatterns/2=dd/MM/y GGGG +FormatData/es/roc.DatePatterns/3=dd/MM/y G +FormatData/es/islamic.DatePatterns/0=EEEE, d 'de' MMMM 'de' y GGGG +FormatData/es/islamic.DatePatterns/1=d 'de' MMMM 'de' y GGGG +FormatData/es/islamic.DatePatterns/2=dd/MM/y GGGG +FormatData/es/islamic.DatePatterns/3=dd/MM/y GGGG +FormatData/et/calendarname.buddhist=budistlik kalender +FormatData/et/calendarname.gregorian=Gregoriuse kalender +FormatData/et/calendarname.gregory=Gregoriuse kalender +FormatData/et/calendarname.islamic-civil=islami ilmalik kalender +FormatData/et/calendarname.islamic=islamikalender +FormatData/et/calendarname.islamicc=islami ilmalik kalender +FormatData/et/calendarname.japanese=Jaapani kalender +FormatData/et/calendarname.roc=Hiina Vabariigi kalender +FormatData/et/field.dayperiod=enne/p\u00e4rast l\u00f5unat +FormatData/et/field.era=ajastu +FormatData/et/field.hour=tund +FormatData/et/field.minute=minut +FormatData/et/field.month=kuu +FormatData/et/field.second=sekund +FormatData/et/field.week=n\u00e4dal +FormatData/et/field.weekday=n\u00e4dalap\u00e4ev +FormatData/et/field.year=aasta +FormatData/et/field.zone=v\u00f6\u00f6nd +FormatData/fi/calendarname.buddhist=buddhalainen kalenteri +FormatData/fi/calendarname.gregorian=gregoriaaninen kalenteri +FormatData/fi/calendarname.gregory=gregoriaaninen kalenteri +FormatData/fi/calendarname.islamic-civil=islamilainen siviilikalenteri +FormatData/fi/calendarname.islamic=islamilainen kalenteri +FormatData/fi/calendarname.islamicc=islamilainen siviilikalenteri +FormatData/fi/calendarname.japanese=japanilainen kalenteri +FormatData/fi/calendarname.roc=Kiinan tasavallan kalenteri +FormatData/fi/field.dayperiod=vuorokaudenaika +FormatData/fi/field.era=aikakausi +FormatData/fi/field.hour=tunti +FormatData/fi/field.minute=minuutti +FormatData/fi/field.month=kuukausi +FormatData/fi/field.second=sekunti +FormatData/fi/field.week=viikko +FormatData/fi/field.weekday=viikonp\u00e4iv\u00e4 +FormatData/fi/field.year=vuosi +FormatData/fi/field.zone=aikavy\u00f6hyke +FormatData/fi/islamic.MonthNames/0=muharram +FormatData/fi/islamic.MonthNames/1=safar +FormatData/fi/islamic.MonthNames/2=rabi\u2019 al-awwal +FormatData/fi/islamic.MonthNames/3=rabi\u2019 al-akhir +FormatData/fi/islamic.MonthNames/4=d\u017eumada-l-ula +FormatData/fi/islamic.MonthNames/5=d\u017eumada-l-akhira +FormatData/fi/islamic.MonthNames/6=rad\u017eab +FormatData/fi/islamic.MonthNames/7=\u0161a\u2019ban +FormatData/fi/islamic.MonthNames/8=ramadan +FormatData/fi/islamic.MonthNames/9=\u0161awwal +FormatData/fi/islamic.MonthNames/10=dhu-l-qa\u2019da +FormatData/fi/islamic.MonthNames/11=dhu-l-hidd\u017ea +FormatData/fi/islamic.MonthNames/12= +FormatData/fi/roc.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/fi/roc.DatePatterns/1=d. MMMM y GGGG +FormatData/fi/roc.DatePatterns/2=d.M.y GGGG +FormatData/fi/roc.DatePatterns/3=d.M.y GGGG +FormatData/fi/islamic.DatePatterns/0=EEEE d. MMMM y GGGG +FormatData/fi/islamic.DatePatterns/1=d. MMMM y GGGG +FormatData/fi/islamic.DatePatterns/2=d.M.y GGGG +FormatData/fi/islamic.DatePatterns/3=d.M.y GGGG +FormatData/fr/calendarname.buddhist=Calendrier bouddhiste +FormatData/fr/calendarname.gregorian=Calendrier gr\u00e9gorien +FormatData/fr/calendarname.gregory=Calendrier gr\u00e9gorien +FormatData/fr/calendarname.islamic-civil=Calendrier civil musulman +FormatData/fr/calendarname.islamic=Calendrier musulman +FormatData/fr/calendarname.islamicc=Calendrier civil musulman +FormatData/fr/calendarname.japanese=Calendrier japonais +FormatData/fr/calendarname.roc=Calendrier r\u00e9publicain chinois +FormatData/fr/field.dayperiod=cadran +FormatData/fr/field.era=\u00e8re +FormatData/fr/field.hour=heure +FormatData/fr/field.minute=minute +FormatData/fr/field.month=mois +FormatData/fr/field.second=seconde +FormatData/fr/field.week=semaine +FormatData/fr/field.weekday=jour de la semaine +FormatData/fr/field.year=ann\u00e9e +FormatData/fr/field.zone=fuseau horaire +FormatData/fr/islamic.MonthNames/0=Mouharram +FormatData/fr/islamic.MonthNames/1=Safar +FormatData/fr/islamic.MonthNames/2=Rabi\u02bb-oul-Aououal +FormatData/fr/islamic.MonthNames/3=Rabi\u02bb-out-Tani +FormatData/fr/islamic.MonthNames/4=Djoumada-l-Oula +FormatData/fr/islamic.MonthNames/5=Djoumada-t-Tania +FormatData/fr/islamic.MonthNames/6=Radjab +FormatData/fr/islamic.MonthNames/7=Cha\u02bbban +FormatData/fr/islamic.MonthNames/8=Ramadan +FormatData/fr/islamic.MonthNames/9=Chaououal +FormatData/fr/islamic.MonthNames/10=Dou-l-Qa\u02bbda +FormatData/fr/islamic.MonthNames/11=Dou-l-Hidjja +FormatData/fr/islamic.MonthNames/12= +FormatData/fr/islamic.MonthAbbreviations/0=Mouh. +FormatData/fr/islamic.MonthAbbreviations/1=Saf. +FormatData/fr/islamic.MonthAbbreviations/2=Rabi\u02bb-oul-A. +FormatData/fr/islamic.MonthAbbreviations/3=Rabi\u02bb-out-T. +FormatData/fr/islamic.MonthAbbreviations/4=Djoum.-l-O. +FormatData/fr/islamic.MonthAbbreviations/5=Djoum.-t-T. +FormatData/fr/islamic.MonthAbbreviations/6=Radj. +FormatData/fr/islamic.MonthAbbreviations/7=Cha. +FormatData/fr/islamic.MonthAbbreviations/8=Ram. +FormatData/fr/islamic.MonthAbbreviations/9=Chaou. +FormatData/fr/islamic.MonthAbbreviations/10=Dou-l-Q. +FormatData/fr/islamic.MonthAbbreviations/11=Dou-l-H. +FormatData/fr/islamic.MonthAbbreviations/12= +FormatData/fr/islamic.Eras/0= +FormatData/fr/islamic.Eras/1=AH +FormatData/fr/roc.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/fr/roc.DatePatterns/1=d MMMM y GGGG +FormatData/fr/roc.DatePatterns/2=d MMM, y GGGG +FormatData/fr/roc.DatePatterns/3=d/M/y G +FormatData/fr/islamic.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/fr/islamic.DatePatterns/1=d MMMM y GGGG +FormatData/fr/islamic.DatePatterns/2=d MMM, y GGGG +FormatData/fr/islamic.DatePatterns/3=d/M/y GGGG +FormatData/hi_IN/calendarname.buddhist=\u092c\u094c\u0926\u094d\u0927 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.gregorian=\u0917\u094d\u0930\u0947\u0917\u0930\u0940 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.gregory=\u0917\u094d\u0930\u0947\u0917\u0930\u0940 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.islamic-civil=\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u0928\u093e\u0917\u0930\u093f\u0915 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.islamic=\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.islamicc=\u0907\u0938\u094d\u0932\u093e\u092e\u0940 \u0928\u093e\u0917\u0930\u093f\u0915 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.japanese=\u091c\u093e\u092a\u093e\u0928\u0940 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/calendarname.roc=\u091a\u0940\u0928\u0940 \u0917\u0923\u0924\u0902\u0924\u094d\u0930 \u092a\u0902\u091a\u093e\u0902\u0917 +FormatData/hi_IN/field.dayperiod=\u0938\u092e\u092f \u0905\u0935\u0927\u093f +FormatData/hi_IN/field.era=\u092f\u0941\u0917 +FormatData/hi_IN/field.hour=\u0918\u0902\u091f\u093e +FormatData/hi_IN/field.minute=\u092e\u093f\u0928\u091f +FormatData/hi_IN/field.month=\u092e\u093e\u0938 +FormatData/hi_IN/field.second=\u0938\u0947\u0915\u0947\u0902\u0921 +FormatData/hi_IN/field.week=\u0938\u092a\u094d\u0924\u093e\u0939 +FormatData/hi_IN/field.weekday=\u0938\u092a\u094d\u0924\u093e\u0939 \u0915\u093e \u0926\u093f\u0928 +FormatData/hi_IN/field.year=\u0935\u0930\u094d\u0937 +FormatData/hi_IN/field.zone=\u0915\u094d\u0937\u0947\u0924\u094d\u0930 +FormatData/hr/calendarname.buddhist=budisti\u010dki kalendar +FormatData/hr/calendarname.gregorian=gregorijanski kalendar +FormatData/hr/calendarname.gregory=gregorijanski kalendar +FormatData/hr/calendarname.islamic-civil=islamski civilni kalendar +FormatData/hr/calendarname.islamic=islamski kalendar +FormatData/hr/calendarname.islamicc=islamski civilni kalendar +FormatData/hr/calendarname.japanese=japanski kalendar +FormatData/hr/calendarname.roc=kalendar Republike Kine +FormatData/hr/field.dayperiod=dio dana +FormatData/hr/field.era=era +FormatData/hr/field.hour=sat +FormatData/hr/field.minute=minuta +FormatData/hr/field.month=mjesec +FormatData/hr/field.second=sekunda +FormatData/hr/field.week=tjedan +FormatData/hr/field.weekday=dan u tjednu +FormatData/hr/field.year=godina +FormatData/hr/field.zone=zona +FormatData/hr/roc.DatePatterns/0=EEEE, d. MMMM y. GGGG +FormatData/hr/roc.DatePatterns/1=d. MMMM y. GGGG +FormatData/hr/roc.DatePatterns/2=d. M. y. GGGG +FormatData/hr/roc.DatePatterns/3=d.M.y. GGGG +FormatData/hu/calendarname.buddhist=buddhista napt\u00e1r +FormatData/hu/calendarname.gregorian=Gergely-napt\u00e1r +FormatData/hu/calendarname.gregory=Gergely-napt\u00e1r +FormatData/hu/calendarname.islamic-civil=iszl\u00e1m civil napt\u00e1r +FormatData/hu/calendarname.islamic=iszl\u00e1m napt\u00e1r +FormatData/hu/calendarname.islamicc=iszl\u00e1m civil napt\u00e1r +FormatData/hu/calendarname.japanese=jap\u00e1n napt\u00e1r +FormatData/hu/calendarname.roc=K\u00ednai k\u00f6zt\u00e1rsas\u00e1gi napt\u00e1r +FormatData/hu/field.dayperiod=napszak +FormatData/hu/field.era=\u00e9ra +FormatData/hu/field.hour=\u00f3ra +FormatData/hu/field.minute=perc +FormatData/hu/field.month=h\u00f3nap +FormatData/hu/field.second=m\u00e1sodperc +FormatData/hu/field.week=h\u00e9t +FormatData/hu/field.weekday=h\u00e9t napja +FormatData/hu/field.year=\u00e9v +FormatData/hu/field.zone=z\u00f3na +FormatData/hu/islamic.MonthNames/0=Moharrem +FormatData/hu/islamic.MonthNames/1=Safar +FormatData/hu/islamic.MonthNames/2=R\u00e9bi el avvel +FormatData/hu/islamic.MonthNames/3=R\u00e9bi el accher +FormatData/hu/islamic.MonthNames/4=Dsem\u00e1di el avvel +FormatData/hu/islamic.MonthNames/5=Dsem\u00e1di el accher +FormatData/hu/islamic.MonthNames/6=Redseb +FormatData/hu/islamic.MonthNames/7=Sab\u00e1n +FormatData/hu/islamic.MonthNames/8=Ramad\u00e1n +FormatData/hu/islamic.MonthNames/9=Sevv\u00e1l +FormatData/hu/islamic.MonthNames/10=Ds\u00fcl kade +FormatData/hu/islamic.MonthNames/11=Ds\u00fcl hedse +FormatData/hu/islamic.MonthNames/12= +FormatData/hu/islamic.Eras/0= +FormatData/hu/islamic.Eras/1=MF +FormatData/is/calendarname.buddhist=B\u00fadd\u00edskt dagatal +FormatData/is/calendarname.gregorian=Gregor\u00edskt dagatal +FormatData/is/calendarname.gregory=Gregor\u00edskt dagatal +FormatData/is/calendarname.islamic-civil=\u00cdslamskt borgaradagatal +FormatData/is/calendarname.islamic=\u00cdslamskt dagatal +FormatData/is/calendarname.islamicc=\u00cdslamskt borgaradagatal +FormatData/is/calendarname.japanese=Japanskt dagatal +FormatData/it/calendarname.buddhist=calendario buddista +FormatData/it/calendarname.gregorian=calendario gregoriano +FormatData/it/calendarname.gregory=calendario gregoriano +FormatData/it/calendarname.islamic-civil=calendario civile islamico +FormatData/it/calendarname.islamic=calendario islamico +FormatData/it/calendarname.islamicc=calendario civile islamico +FormatData/it/calendarname.japanese=calendario giapponese +FormatData/it/field.dayperiod=periodo del giorno +FormatData/it/field.era=era +FormatData/it/field.hour=ora +FormatData/it/field.minute=minuto +FormatData/it/field.month=mese +FormatData/it/field.second=secondo +FormatData/it/field.week=settimana +FormatData/it/field.weekday=giorno della settimana +FormatData/it/field.year=anno +FormatData/it/field.zone=zona +FormatData/it/roc.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/it/roc.DatePatterns/1=dd MMMM y GGGG +FormatData/it/roc.DatePatterns/2=dd/MMM/y GGGG +FormatData/it/roc.DatePatterns/3=dd/MM/y GGGG +FormatData/it/islamic.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/it/islamic.DatePatterns/1=dd MMMM y GGGG +FormatData/it/islamic.DatePatterns/2=dd/MMM/y GGGG +FormatData/it/islamic.DatePatterns/3=dd/MM/y GGGG +FormatData/iw/calendarname.buddhist=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d1\u05d5\u05d3\u05d4\u05d9\u05e1\u05d8\u05d9 +FormatData/iw/calendarname.gregorian=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d2\u05e8\u05d2\u05d5\u05e8\u05d9\u05d0\u05e0\u05d9 +FormatData/iw/calendarname.gregory=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d2\u05e8\u05d2\u05d5\u05e8\u05d9\u05d0\u05e0\u05d9 +FormatData/iw/calendarname.islamic-civil=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9-\u05d0\u05d6\u05e8\u05d7\u05d9 +FormatData/iw/calendarname.islamic=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9 +FormatData/iw/calendarname.islamicc=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05de\u05d5\u05e1\u05dc\u05de\u05d9-\u05d0\u05d6\u05e8\u05d7\u05d9 +FormatData/iw/calendarname.japanese=\u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05d9\u05e4\u05e0\u05d9 +FormatData/iw/field.dayperiod=\u05dc\u05e4\u05d4\u05f4\u05e6/\u05d0\u05d7\u05d4\u05f4\u05e6 +FormatData/iw/field.era=\u05ea\u05e7\u05d5\u05e4\u05d4 +FormatData/iw/field.hour=\u05e9\u05e2\u05d4 +FormatData/iw/field.minute=\u05d3\u05e7\u05d4 +FormatData/iw/field.month=\u05d7\u05d5\u05d3\u05e9 +FormatData/iw/field.second=\u05e9\u05e0\u05d9\u05d9\u05d4 +FormatData/iw/field.week=\u05e9\u05d1\u05d5\u05e2 +FormatData/iw/field.weekday=\u05d9\u05d5\u05dd \u05d1\u05e9\u05d1\u05d5\u05e2 +FormatData/iw/field.year=\u05e9\u05e0\u05d4 +FormatData/iw/field.zone=\u05d0\u05d6\u05d5\u05e8 +FormatData/iw/islamic.MonthNames/0=\u05de\u05d5\u05d7\u05e8\u05dd +FormatData/iw/islamic.MonthNames/1=\u05e1\u05e4\u05e8 +FormatData/iw/islamic.MonthNames/2=\u05e8\u05d1\u05d9\u05e2 \u05d0\u05dc-\u05d0\u05d5\u05d5\u05d0\u05dc +FormatData/iw/islamic.MonthNames/3=\u05e8\u05d1\u05d9\u05e2 \u05d0\u05dc-\u05ea\u05e0\u05d9 +FormatData/iw/islamic.MonthNames/4=\u05d2\u05f3\u05d5\u05de\u05d3\u05d4 \u05d0\u05dc-\u05d0\u05d5\u05d5\u05d0\u05dc +FormatData/iw/islamic.MonthNames/5=\u05d2\u05f3\u05d5\u05de\u05d3\u05d4 \u05d0\u05dc-\u05ea\u05e0\u05d9 +FormatData/iw/islamic.MonthNames/6=\u05e8\u05d2\u05f3\u05d0\u05d1 +FormatData/iw/islamic.MonthNames/7=\u05e9\u05e2\u05d1\u05d0\u05df +FormatData/iw/islamic.MonthNames/8=\u05e8\u05d0\u05de\u05d3\u05df +FormatData/iw/islamic.MonthNames/9=\u05e9\u05d5\u05d5\u05d0\u05dc +FormatData/iw/islamic.MonthNames/10=\u05d6\u05d5 \u05d0\u05dc-QI'DAH +FormatData/iw/islamic.MonthNames/11=\u05d6\u05d5 \u05d0\u05dc-\u05d7\u05d9\u05d2\u05f3\u05d4 +FormatData/iw/islamic.MonthNames/12= +FormatData/iw/islamic.Eras/0= +FormatData/iw/islamic.Eras/1=\u05e9\u05e0\u05ea \u05d4\u05d9\u05d2\u05f3\u05e8\u05d4 +FormatData/ja/calendarname.buddhist=\u30bf\u30a4\u4ecf\u6559\u66a6 +FormatData/ja/calendarname.gregorian=\u897f\u66a6[\u30b0\u30ec\u30b4\u30ea\u30aa\u66a6] +FormatData/ja/calendarname.gregory=\u897f\u66a6[\u30b0\u30ec\u30b4\u30ea\u30aa\u66a6] +FormatData/ja/calendarname.islamic-civil=\u592a\u967d\u30a4\u30b9\u30e9\u30e0\u66a6 +FormatData/ja/calendarname.islamic=\u30a4\u30b9\u30e9\u30e0\u66a6 +FormatData/ja/calendarname.islamicc=\u592a\u967d\u30a4\u30b9\u30e9\u30e0\u66a6 +FormatData/ja/calendarname.japanese=\u548c\u66a6 +FormatData/ja/calendarname.roc=\u4e2d\u83ef\u6c11\u56fd\u66a6 +FormatData/ja/field.dayperiod=\u5348\u524d/\u5348\u5f8c +FormatData/ja/field.era=\u6642\u4ee3 +FormatData/ja/field.hour=\u6642 +FormatData/ja/field.minute=\u5206 +FormatData/ja/field.month=\u6708 +FormatData/ja/field.second=\u79d2 +FormatData/ja/field.week=\u9031 +FormatData/ja/field.weekday=\u66dc\u65e5 +FormatData/ja/field.year=\u5e74 +FormatData/ja/field.zone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 +FormatData/ja/roc.DatePatterns/0=GGGGy\u5e74M\u6708d\u65e5EEEE +FormatData/ja/roc.DatePatterns/1=GGGGy\u5e74M\u6708d\u65e5 +FormatData/ja/roc.DatePatterns/2=GGGGy/MM/dd +FormatData/ja/roc.DatePatterns/3=GGGGy/MM/dd +FormatData/ko/calendarname.buddhist=\ubd88\uad50\ub825 +FormatData/ko/calendarname.gregorian=\ud0dc\uc591\ub825 +FormatData/ko/calendarname.gregory=\ud0dc\uc591\ub825 +FormatData/ko/calendarname.islamic-civil=\uc774\uc2ac\ub78c \uc0c1\uc6a9\ub825 +FormatData/ko/calendarname.islamic=\uc774\uc2ac\ub78c\ub825 +FormatData/ko/calendarname.islamicc=\uc774\uc2ac\ub78c \uc0c1\uc6a9\ub825 +FormatData/ko/calendarname.japanese=\uc77c\ubcf8\ub825 +FormatData/ko/calendarname.roc=\ub300\ub9cc\ub825 +FormatData/ko/field.dayperiod=\uc624\uc804/\uc624\ud6c4 +FormatData/ko/field.era=\uc5f0\ud638 +FormatData/ko/field.hour=\uc2dc +FormatData/ko/field.minute=\ubd84 +FormatData/ko/field.month=\uc6d4 +FormatData/ko/field.second=\ucd08 +FormatData/ko/field.week=\uc8fc +FormatData/ko/field.weekday=\uc694\uc77c +FormatData/ko/field.year=\ub144 +FormatData/ko/field.zone=\uc2dc\uac04\ub300 +FormatData/ko/roc.DatePatterns/0=GGGG y\ub144 M\uc6d4 d\uc77c EEEE +FormatData/ko/roc.DatePatterns/1=GGGG y\ub144 M\uc6d4 d\uc77c +FormatData/ko/roc.DatePatterns/2=GGGG y. M. d +FormatData/ko/roc.DatePatterns/3=GGGG y. M. d +FormatData/lt/calendarname.buddhist=Budist\u0173 kalendorius +FormatData/lt/calendarname.gregorian=Grigaliaus kalendorius +FormatData/lt/calendarname.gregory=Grigaliaus kalendorius +FormatData/lt/calendarname.islamic-civil=Pilietinis islamo kalendorius +FormatData/lt/calendarname.islamic=Islamo kalendorius +FormatData/lt/calendarname.islamicc=Pilietinis islamo kalendorius +FormatData/lt/calendarname.japanese=Japon\u0173 kalendorius +FormatData/lt/calendarname.roc=Kinijos Respublikos kalendorius +FormatData/lt/field.dayperiod=dienos metas +FormatData/lt/field.era=era +FormatData/lt/field.hour=valanda +FormatData/lt/field.minute=minut\u0117 +FormatData/lt/field.month=m\u0117nuo +FormatData/lt/field.second=sekund\u0117 +FormatData/lt/field.week=savait\u0117 +FormatData/lt/field.weekday=savait\u0117s diena +FormatData/lt/field.year=metai +FormatData/lt/field.zone=laiko juosta +FormatData/lv/calendarname.buddhist=budistu kalend\u0101rs +FormatData/lv/calendarname.gregorian=Gregora kalend\u0101rs +FormatData/lv/calendarname.gregory=Gregora kalend\u0101rs +FormatData/lv/calendarname.islamic-civil=isl\u0101ma pilso\u0146u kalend\u0101rs +FormatData/lv/calendarname.islamic=isl\u0101ma kalend\u0101rs +FormatData/lv/calendarname.islamicc=isl\u0101ma pilso\u0146u kalend\u0101rs +FormatData/lv/calendarname.japanese=jap\u0101\u0146u kalend\u0101rs +FormatData/lv/calendarname.roc=\u0136\u012bnas Republikas kalend\u0101rs +FormatData/lv/field.dayperiod=Dayperiod +FormatData/lv/field.era=\u0113ra +FormatData/lv/field.hour=Stundas +FormatData/lv/field.minute=Min\u016btes +FormatData/lv/field.month=M\u0113nesis +FormatData/lv/field.second=Sekundes +FormatData/lv/field.week=Ned\u0113\u013ca +FormatData/lv/field.weekday=Ned\u0113\u013cas diena +FormatData/lv/field.year=Gads +FormatData/lv/field.zone=Josla +FormatData/lv/islamic.MonthNames/0=muharams +FormatData/lv/islamic.MonthNames/1=safars +FormatData/lv/islamic.MonthNames/2=1. rab\u012b +FormatData/lv/islamic.MonthNames/3=2. rab\u012b +FormatData/lv/islamic.MonthNames/4=1. d\u017eum\u0101d\u0101 +FormatData/lv/islamic.MonthNames/5=2. d\u017eum\u0101d\u0101 +FormatData/lv/islamic.MonthNames/6=rad\u017eabs +FormatData/lv/islamic.MonthNames/7=\u0161abans +FormatData/lv/islamic.MonthNames/8=ramad\u0101ns +FormatData/lv/islamic.MonthNames/9=\u0161auvals +FormatData/lv/islamic.MonthNames/10=du al-kid\u0101 +FormatData/lv/islamic.MonthNames/11=du al-hid\u017e\u0101 +FormatData/lv/islamic.MonthNames/12= +FormatData/mk/calendarname.buddhist=\u0411\u0443\u0434\u0438\u0441\u0442\u0438\u0447\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.gregorian=\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.gregory=\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.islamic-civil=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0433\u0440\u0430\u0453\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.islamic=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.islamicc=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0433\u0440\u0430\u0453\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.japanese=\u0408\u0430\u043f\u043e\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/mk/calendarname.roc=\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u043d\u0430 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0430 \u041a\u0438\u043d\u0430 +FormatData/mk/field.dayperiod=\u043f\u0440\u0435\u0442\u043f\u043b\u0430\u0434\u043d\u0435/\u043f\u043e\u043f\u043b\u0430\u0434\u043d\u0435 +FormatData/mk/field.era=\u0415\u0440\u0430 +FormatData/mk/field.hour=\u0427\u0430\u0441 +FormatData/mk/field.minute=\u041c\u0438\u043d\u0443\u0442\u0430 +FormatData/mk/field.month=\u041c\u0435\u0441\u0435\u0446 +FormatData/mk/field.second=\u0421\u0435\u043a\u0443\u043d\u0434\u0430 +FormatData/mk/field.week=\u041d\u0435\u0434\u0435\u043b\u0430 +FormatData/mk/field.weekday=\u0414\u0435\u043d \u0432\u043e \u043d\u0435\u0434\u0435\u043b\u0430\u0442\u0430 +FormatData/mk/field.year=\u0433\u043e\u0434\u0438\u043d\u0430 +FormatData/mk/field.zone=\u0437\u043e\u043d\u0430 +FormatData/ms/calendarname.buddhist=Kalendar Buddha +FormatData/ms/calendarname.gregorian=Kalendar Gregory +FormatData/ms/calendarname.gregory=Kalendar Gregory +FormatData/ms/calendarname.islamic-civil=Kalendar Sivil Islam +FormatData/ms/calendarname.islamic=Kalendar Islam +FormatData/ms/calendarname.islamicc=Kalendar Sivil Islam +FormatData/ms/calendarname.japanese=Kalendar Jepun +FormatData/ms/calendarname.roc=Kalendar Minguo +FormatData/ms/field.dayperiod=PG/PTG +FormatData/ms/field.hour=Jam +FormatData/ms/field.minute=Minit +FormatData/ms/field.month=Bulan +FormatData/ms/field.second=Kedua +FormatData/ms/field.week=Minggu +FormatData/ms/field.weekday=Hari dalam Minggu +FormatData/ms/field.year=Tahun +FormatData/ms/field.zone=Zon Waktu +FormatData/ms/roc.DatePatterns/0=EEEE, d MMMM y GGGG +FormatData/ms/roc.DatePatterns/1=d MMMM y GGGG +FormatData/ms/roc.DatePatterns/2=dd/MM/y GGGG +FormatData/ms/roc.DatePatterns/3=d/MM/y GGGG +FormatData/ms/islamic.DatePatterns/0=EEEE, d MMMM y GGGG +FormatData/ms/islamic.DatePatterns/1=d MMMM y GGGG +FormatData/ms/islamic.DatePatterns/2=dd/MM/y GGGG +FormatData/ms/islamic.DatePatterns/3=d/MM/y GGGG +FormatData/mt/calendarname.buddhist=Kalendarju Buddist +FormatData/mt/calendarname.gregorian=Kalendarju Gregorjan +FormatData/mt/calendarname.gregory=Kalendarju Gregorjan +FormatData/mt/calendarname.islamic-civil=Kalendarju Islamiku-\u010aivili +FormatData/mt/calendarname.islamic=Kalendarju Islamiku +FormatData/mt/calendarname.islamicc=Kalendarju Islamiku-\u010aivili +FormatData/mt/calendarname.japanese=Kalendarju \u0120appuni\u017c +FormatData/mt/field.era=Epoka +FormatData/mt/field.hour=Sieg\u0127a +FormatData/mt/field.minute=Minuta +FormatData/mt/field.month=Xahar +FormatData/mt/field.second=Sekonda +FormatData/mt/field.week=\u0120img\u0127a +FormatData/mt/field.weekday=Jum tal-\u0120img\u0127a +FormatData/mt/field.year=Sena +FormatData/mt/field.zone=\u017bona +FormatData/nl/calendarname.buddhist=Boeddhistische kalender +FormatData/nl/calendarname.gregorian=Gregoriaanse kalender +FormatData/nl/calendarname.gregory=Gregoriaanse kalender +FormatData/nl/calendarname.islamic-civil=Islamitische kalender (cyclisch) +FormatData/nl/calendarname.islamic=Islamitische kalender +FormatData/nl/calendarname.islamicc=Islamitische kalender (cyclisch) +FormatData/nl/calendarname.japanese=Japanse kalender +FormatData/nl/calendarname.roc=Kalender van de Chinese Republiek +FormatData/nl/field.dayperiod=AM/PM +FormatData/nl/field.era=Tijdperk +FormatData/nl/field.hour=Uur +FormatData/nl/field.minute=Minuut +FormatData/nl/field.month=Maand +FormatData/nl/field.second=Seconde +FormatData/nl/field.weekday=Dag van de week +FormatData/nl/field.year=Jaar +FormatData/nl/field.zone=Zone +FormatData/nl/islamic.MonthNames/0=Moeharram +FormatData/nl/islamic.MonthNames/1=Safar +FormatData/nl/islamic.MonthNames/2=Rabi\u02bba al awal +FormatData/nl/islamic.MonthNames/3=Rabi\u02bba al thani +FormatData/nl/islamic.MonthNames/4=Joemad\u02bbal awal +FormatData/nl/islamic.MonthNames/5=Joemad\u02bbal thani +FormatData/nl/islamic.MonthNames/6=Rajab +FormatData/nl/islamic.MonthNames/7=Sja\u02bbaban +FormatData/nl/islamic.MonthNames/8=Ramadan +FormatData/nl/islamic.MonthNames/9=Sjawal +FormatData/nl/islamic.MonthNames/10=Doe al ka\u02bbaba +FormatData/nl/islamic.MonthNames/11=Doe al hizja +FormatData/nl/islamic.MonthNames/12= +FormatData/nl/islamic.MonthAbbreviations/0=Moeh. +FormatData/nl/islamic.MonthAbbreviations/1=Saf. +FormatData/nl/islamic.MonthAbbreviations/2=Rab. I +FormatData/nl/islamic.MonthAbbreviations/3=Rab. II +FormatData/nl/islamic.MonthAbbreviations/4=Joem. I +FormatData/nl/islamic.MonthAbbreviations/5=Joem. II +FormatData/nl/islamic.MonthAbbreviations/6=Raj. +FormatData/nl/islamic.MonthAbbreviations/7=Sja. +FormatData/nl/islamic.MonthAbbreviations/8=Ram. +FormatData/nl/islamic.MonthAbbreviations/9=Sjaw. +FormatData/nl/islamic.MonthAbbreviations/10=Doe al k. +FormatData/nl/islamic.MonthAbbreviations/11=Doe al h. +FormatData/nl/islamic.MonthAbbreviations/12= +FormatData/nl/islamic.Eras/0= +FormatData/nl/islamic.Eras/1=Sa\u02bbna Hizjria +FormatData/nl/roc.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/nl/roc.DatePatterns/1=d MMMM y GGGG +FormatData/nl/roc.DatePatterns/2=d MMM y GGGG +FormatData/nl/roc.DatePatterns/3=dd-MM-yy G +FormatData/nl/islamic.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/nl/islamic.DatePatterns/1=d MMMM y GGGG +FormatData/nl/islamic.DatePatterns/2=d MMM y GGGG +FormatData/nl/islamic.DatePatterns/3=dd-MM-yy GGGG +FormatData/pl/calendarname.buddhist=kalendarz buddyjski +FormatData/pl/calendarname.gregorian=kalendarz gregoria\u0144ski +FormatData/pl/calendarname.gregory=kalendarz gregoria\u0144ski +FormatData/pl/calendarname.islamic-civil=kalendarz islamski (metoda obliczeniowa) +FormatData/pl/calendarname.islamic=kalendarz islamski (metoda wzrokowa) +FormatData/pl/calendarname.islamicc=kalendarz islamski (metoda obliczeniowa) +FormatData/pl/calendarname.japanese=kalendarz japo\u0144ski +FormatData/pl/calendarname.roc=kalendarz Republiki Chi\u0144skiej +FormatData/pl/field.era=Era +FormatData/pl/field.hour=Godzina +FormatData/pl/field.minute=Minuta +FormatData/pl/field.month=Miesi\u0105c +FormatData/pl/field.second=Sekunda +FormatData/pl/field.week=Tydzie\u0144 +FormatData/pl/field.weekday=Dzie\u0144 tygodnia +FormatData/pl/field.year=Rok +FormatData/pl/field.zone=Strefa +FormatData/pl/roc.DatePatterns/0=EEEE, d MMMM, y GGGG +FormatData/pl/roc.DatePatterns/1=d MMMM, y GGGG +FormatData/pl/roc.DatePatterns/2=d MMM y GGGG +FormatData/pl/roc.DatePatterns/3=dd.MM.yyyy GGGG +FormatData/pl/islamic.DatePatterns/0=EEEE, d MMMM, y GGGG +FormatData/pl/islamic.DatePatterns/1=d MMMM, y GGGG +FormatData/pl/islamic.DatePatterns/2=d MMM y GGGG +FormatData/pl/islamic.DatePatterns/3=dd.MM.yyyy GGGG +FormatData/pt/calendarname.buddhist=Calend\u00e1rio Budista +FormatData/pt/calendarname.gregorian=Calend\u00e1rio Gregoriano +FormatData/pt/calendarname.gregory=Calend\u00e1rio Gregoriano +FormatData/pt/calendarname.islamic-civil=Calend\u00e1rio Civil Isl\u00e2mico +FormatData/pt/calendarname.islamic=Calend\u00e1rio Isl\u00e2mico +FormatData/pt/calendarname.islamicc=Calend\u00e1rio Civil Isl\u00e2mico +FormatData/pt/calendarname.japanese=Calend\u00e1rio Japon\u00eas +FormatData/pt/calendarname.roc=Calend\u00e1rio da Rep\u00fablica da China +FormatData/pt/field.dayperiod=Per\u00edodo do dia +FormatData/pt/field.era=Era +FormatData/pt/field.hour=Hora +FormatData/pt/field.minute=Minuto +FormatData/pt/field.month=M\u00eas +FormatData/pt/field.second=Segundo +FormatData/pt/field.week=Semana +FormatData/pt/field.weekday=Dia da semana +FormatData/pt/field.year=Ano +FormatData/pt/field.zone=Fuso +FormatData/pt/roc.DatePatterns/0=EEEE, d 'de' MMMM 'de' y GGGG +FormatData/pt/roc.DatePatterns/1=d 'de' MMMM 'de' y GGGG +FormatData/pt/roc.DatePatterns/2=dd/MM/yyyy GGGG +FormatData/pt/roc.DatePatterns/3=d/M/yyyy +FormatData/pt/islamic.DatePatterns/0=EEEE, d 'de' MMMM 'de' y GGGG +FormatData/pt/islamic.DatePatterns/1=d 'de' MMMM 'de' y GGGG +FormatData/pt/islamic.DatePatterns/2=dd/MM/yyyy GGGG +FormatData/pt/islamic.DatePatterns/3=d/M/yyyy +FormatData/ro/calendarname.buddhist=calendar budist +FormatData/ro/calendarname.gregorian=calendar gregorian +FormatData/ro/calendarname.gregory=calendar gregorian +FormatData/ro/calendarname.islamic-civil=calendar islamic civil +FormatData/ro/calendarname.islamic=calendar islamic +FormatData/ro/calendarname.islamicc=calendar islamic civil +FormatData/ro/calendarname.japanese=calendar japonez +FormatData/ro/calendarname.roc=calendar al Republicii Chineze +FormatData/ro/field.dayperiod=perioada zilei +FormatData/ro/field.era=er\u0103 +FormatData/ro/field.hour=or\u0103 +FormatData/ro/field.minute=minut +FormatData/ro/field.month=lun\u0103 +FormatData/ro/field.second=secund\u0103 +FormatData/ro/field.week=s\u0103pt\u0103m\u00e2n\u0103 +FormatData/ro/field.weekday=zi a s\u0103pt\u0103m\u00e2nii +FormatData/ro/field.year=an +FormatData/ro/field.zone=zon\u0103 +FormatData/ru/calendarname.buddhist=\u0411\u0443\u0434\u0434\u0438\u0439\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.gregorian=\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.gregory=\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.islamic-civil=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.islamic=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.islamicc=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438\u0439 \u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.japanese=\u042f\u043f\u043e\u043d\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/calendarname.roc=\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c +FormatData/ru/field.era=\u042d\u0440\u0430 +FormatData/ru/field.hour=\u0427\u0430\u0441 +FormatData/ru/field.minute=\u041c\u0438\u043d\u0443\u0442\u0430 +FormatData/ru/field.month=\u041c\u0435\u0441\u044f\u0446 +FormatData/ru/field.second=\u0421\u0435\u043a\u0443\u043d\u0434\u0430 +FormatData/ru/field.week=\u041d\u0435\u0434\u0435\u043b\u044f +FormatData/ru/field.weekday=\u0414\u0435\u043d\u044c \u043d\u0435\u0434\u0435\u043b\u0438 +FormatData/ru/field.year=\u0413\u043e\u0434 +FormatData/ru/field.zone=\u0427\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 +FormatData/ru/islamic.MonthNames/0=\u041c\u0443\u0445\u0430\u0440\u0440\u0430\u043c +FormatData/ru/islamic.MonthNames/1=\u0421\u0430\u0444\u0430\u0440 +FormatData/ru/islamic.MonthNames/2=\u0420\u0430\u0431\u0438-\u0443\u043b\u044c-\u0430\u0432\u0432\u0430\u043b\u044c +FormatData/ru/islamic.MonthNames/3=\u0420\u0430\u0431\u0438-\u0443\u043b\u044c-\u0430\u0445\u0438\u0440 +FormatData/ru/islamic.MonthNames/4=\u0414\u0436\u0443\u043c\u0430\u0434-\u0443\u043b\u044c-\u0430\u0432\u0432\u0430\u043b\u044c +FormatData/ru/islamic.MonthNames/5=\u0414\u0436\u0443\u043c\u0430\u0434-\u0443\u043b\u044c-\u0430\u0445\u0438\u0440 +FormatData/ru/islamic.MonthNames/6=\u0420\u0430\u0434\u0436\u0430\u0431 +FormatData/ru/islamic.MonthNames/7=\u0428\u0430\u0430\u0431\u0430\u043d +FormatData/ru/islamic.MonthNames/8=\u0420\u0430\u043c\u0430\u0434\u0430\u043d +FormatData/ru/islamic.MonthNames/9=\u0428\u0430\u0432\u0432\u0430\u043b\u044c +FormatData/ru/islamic.MonthNames/10=\u0417\u0443\u043b\u044c-\u041a\u0430\u0430\u0434\u0430 +FormatData/ru/islamic.MonthNames/11=\u0417\u0443\u043b\u044c-\u0425\u0438\u0434\u0436\u0436\u0430 +FormatData/ru/islamic.MonthNames/12= +FormatData/ru/roc.DatePatterns/0=EEEE, d MMMM y\u00a0'\u0433'. GGGG +FormatData/ru/roc.DatePatterns/1=d MMMM y\u00a0'\u0433'. GGGG +FormatData/ru/roc.DatePatterns/2=dd.MM.yyyy GGGG +FormatData/ru/roc.DatePatterns/3=dd.MM.yy GGGG +FormatData/ru/islamic.DatePatterns/0=EEEE, d MMMM y\u00a0'\u0433'. GGGG +FormatData/ru/islamic.DatePatterns/1=d MMMM y\u00a0'\u0433'. GGGG +FormatData/ru/islamic.DatePatterns/2=dd.MM.yyyy GGGG +FormatData/ru/islamic.DatePatterns/3=dd.MM.yy GGGG +FormatData/sk/calendarname.buddhist=Buddhistick\u00fd kalend\u00e1r +FormatData/sk/calendarname.gregorian=Gregori\u00e1nsky kalend\u00e1r +FormatData/sk/calendarname.gregory=Gregori\u00e1nsky kalend\u00e1r +FormatData/sk/calendarname.islamic-civil=Islamsk\u00fd ob\u010diansky kalend\u00e1r +FormatData/sk/calendarname.islamic=Islamsk\u00fd kalend\u00e1r +FormatData/sk/calendarname.islamicc=Islamsk\u00fd ob\u010diansky kalend\u00e1r +FormatData/sk/calendarname.japanese=Japonsk\u00fd kalend\u00e1r +FormatData/sk/field.dayperiod=\u010cas\u0165 d\u0148a +FormatData/sk/field.era=\u00c9ra +FormatData/sk/field.hour=Hodina +FormatData/sk/field.minute=Min\u00fata +FormatData/sk/field.month=Mesiac +FormatData/sk/field.second=Sekunda +FormatData/sk/field.week=T\u00fd\u017ede\u0148 +FormatData/sk/field.weekday=De\u0148 v t\u00fd\u017edni +FormatData/sk/field.year=Rok +FormatData/sk/field.zone=P\u00e1smo +FormatData/sl/calendarname.buddhist=budisti\u010dni koledar +FormatData/sl/calendarname.gregorian=gregorijanski koledar +FormatData/sl/calendarname.gregory=gregorijanski koledar +FormatData/sl/calendarname.islamic-civil=islamski civilni koledar +FormatData/sl/calendarname.islamic=islamski koledar +FormatData/sl/calendarname.islamicc=islamski civilni koledar +FormatData/sl/calendarname.japanese=japonski koledar +FormatData/sl/calendarname.roc=kitajski dr\u017eavni koledar +FormatData/sl/field.dayperiod=\u010cas dneva +FormatData/sl/field.era=Doba +FormatData/sl/field.hour=Ura +FormatData/sl/field.minute=Minuta +FormatData/sl/field.month=Mesec +FormatData/sl/field.second=Sekunda +FormatData/sl/field.week=Teden +FormatData/sl/field.weekday=Dan v tednu +FormatData/sl/field.year=Leto +FormatData/sl/field.zone=Obmo\u010dje +FormatData/sr/calendarname.buddhist=\u0411\u0443\u0434\u0438\u0441\u0442\u0438\u0447\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.gregorian=\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.gregory=\u0413\u0440\u0435\u0433\u043e\u0440\u0438\u0458\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.islamic-civil=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u043d\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.islamic=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.islamicc=\u0418\u0441\u043b\u0430\u043c\u0441\u043a\u0438 \u0446\u0438\u0432\u0438\u043b\u043d\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.japanese=\u0408\u0430\u043f\u0430\u043d\u0441\u043a\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/sr/calendarname.roc=\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 \u0420\u0435\u043f\u0443\u0431\u043b\u0438\u043a\u0435 \u041a\u0438\u043d\u0435 +FormatData/sr/field.dayperiod=\u043f\u0440\u0435 \u043f\u043e\u0434\u043d\u0435/\u043f\u043e\u043f\u043e\u0434\u043d\u0435 +FormatData/sr/field.era=\u0435\u0440\u0430 +FormatData/sr/field.hour=\u0447\u0430\u0441 +FormatData/sr/field.minute=\u043c\u0438\u043d\u0443\u0442 +FormatData/sr/field.month=\u043c\u0435\u0441\u0435\u0446 +FormatData/sr/field.second=\u0441\u0435\u043a\u0443\u043d\u0434 +FormatData/sr/field.week=\u043d\u0435\u0434\u0435\u0459\u0430 +FormatData/sr/field.weekday=\u0434\u0430\u043d \u0443 \u043d\u0435\u0434\u0435\u0459\u0438 +FormatData/sr/field.year=\u0433\u043e\u0434\u0438\u043d\u0430 +FormatData/sr/field.zone=\u0437\u043e\u043d\u0430 +FormatData/sr/islamic.MonthNames/0=\u041c\u0443\u0440\u0430\u0445\u0430\u043c +FormatData/sr/islamic.MonthNames/1=\u0421\u0430\u0444\u0430\u0440 +FormatData/sr/islamic.MonthNames/2=\u0420\u0430\u0431\u0438\u02bb I +FormatData/sr/islamic.MonthNames/3=\u0420\u0430\u0431\u0438\u02bb II +FormatData/sr/islamic.MonthNames/4=\u0408\u0443\u043c\u0430\u0434\u0430 I +FormatData/sr/islamic.MonthNames/5=\u0408\u0443\u043c\u0430\u0434\u0430 II +FormatData/sr/islamic.MonthNames/6=\u0420\u0430\u0452\u0430\u0431 +FormatData/sr/islamic.MonthNames/7=\u0428\u0430\u02bb\u0431\u0430\u043d +FormatData/sr/islamic.MonthNames/8=\u0420\u0430\u043c\u0430\u0434\u0430\u043d +FormatData/sr/islamic.MonthNames/9=\u0428\u0430\u0432\u0430\u043b +FormatData/sr/islamic.MonthNames/10=\u0414\u0443\u02bb\u043b-\u041a\u0438\u02bb\u0434\u0430 +FormatData/sr/islamic.MonthNames/11=\u0414\u0443\u02bb\u043b-\u0445\u0438\u0452\u0430 +FormatData/sr/islamic.MonthNames/12= +FormatData/sr/islamic.Eras/0= +FormatData/sr/islamic.Eras/1=\u0410\u0425 +FormatData/sv/calendarname.buddhist=buddistisk kalender +FormatData/sv/calendarname.gregorian=gregoriansk kalender +FormatData/sv/calendarname.gregory=gregoriansk kalender +FormatData/sv/calendarname.islamic-civil=islamisk civil kalender +FormatData/sv/calendarname.islamic=islamisk kalender +FormatData/sv/calendarname.islamicc=islamisk civil kalender +FormatData/sv/calendarname.japanese=japansk kalender +FormatData/sv/calendarname.roc=kinesiska republikens kalender +FormatData/sv/field.dayperiod=fm/em +FormatData/sv/field.era=era +FormatData/sv/field.hour=timme +FormatData/sv/field.minute=minut +FormatData/sv/field.month=m\u00e5nad +FormatData/sv/field.second=sekund +FormatData/sv/field.week=vecka +FormatData/sv/field.weekday=veckodag +FormatData/sv/field.year=\u00e5r +FormatData/sv/field.zone=tidszon +FormatData/sv/roc.Eras/0=f\u00f6re R.K. +FormatData/sv/roc.Eras/1=R.K. +FormatData/sv/roc.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/sv/roc.DatePatterns/1=d MMMM y GGGG +FormatData/sv/roc.DatePatterns/2=d MMM y GGGG +FormatData/sv/roc.DatePatterns/3=GGGG y-MM-dd +FormatData/sv/islamic.DatePatterns/0=EEEE d MMMM y GGGG +FormatData/sv/islamic.DatePatterns/1=d MMMM y GGGG +FormatData/sv/islamic.DatePatterns/2=d MMM y GGGG +FormatData/sv/islamic.DatePatterns/3=GGGG y-MM-dd +FormatData/th/calendarname.buddhist=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e1e\u0e38\u0e17\u0e18 +FormatData/th/calendarname.gregorian=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e40\u0e01\u0e23\u0e01\u0e2d\u0e40\u0e23\u0e35\u0e22\u0e19 +FormatData/th/calendarname.gregory=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e40\u0e01\u0e23\u0e01\u0e2d\u0e40\u0e23\u0e35\u0e22\u0e19 +FormatData/th/calendarname.islamic-civil=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21\u0e0b\u0e35\u0e27\u0e34\u0e25 +FormatData/th/calendarname.islamic=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21 +FormatData/th/calendarname.islamicc=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2d\u0e34\u0e2a\u0e25\u0e32\u0e21\u0e0b\u0e35\u0e27\u0e34\u0e25 +FormatData/th/calendarname.japanese=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e0d\u0e35\u0e48\u0e1b\u0e38\u0e48\u0e19 +FormatData/th/calendarname.roc=\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e44\u0e15\u0e49\u0e2b\u0e27\u0e31\u0e19 +FormatData/th/field.dayperiod=\u0e0a\u0e48\u0e27\u0e07\u0e27\u0e31\u0e19 +FormatData/th/field.era=\u0e2a\u0e21\u0e31\u0e22 +FormatData/th/field.hour=\u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07 +FormatData/th/field.minute=\u0e19\u0e32\u0e17\u0e35 +FormatData/th/field.month=\u0e40\u0e14\u0e37\u0e2d\u0e19 +FormatData/th/field.second=\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35 +FormatData/th/field.week=\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c +FormatData/th/field.weekday=\u0e27\u0e31\u0e19\u0e43\u0e19\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c +FormatData/th/field.year=\u0e1b\u0e35 +FormatData/th/field.zone=\u0e40\u0e02\u0e15 +FormatData/th/islamic.MonthNames/0=\u0e21\u0e38\u0e2e\u0e30\u0e23\u0e4c\u0e23\u0e2d\u0e21 +FormatData/th/islamic.MonthNames/1=\u0e0b\u0e2d\u0e1f\u0e32\u0e23\u0e4c +FormatData/th/islamic.MonthNames/2=\u0e23\u0e2d\u0e1a\u0e35 I +FormatData/th/islamic.MonthNames/3=\u0e23\u0e2d\u0e1a\u0e35 II +FormatData/th/islamic.MonthNames/4=\u0e08\u0e38\u0e21\u0e32\u0e14\u0e32 I +FormatData/th/islamic.MonthNames/5=\u0e08\u0e38\u0e21\u0e32\u0e14\u0e32 II +FormatData/th/islamic.MonthNames/6=\u0e23\u0e2d\u0e08\u0e31\u0e1a +FormatData/th/islamic.MonthNames/7=\u0e0a\u0e30\u0e2d\u0e30\u0e1a\u0e32\u0e19 +FormatData/th/islamic.MonthNames/8=\u0e23\u0e2d\u0e21\u0e30\u0e14\u0e2d\u0e19 +FormatData/th/islamic.MonthNames/9=\u0e40\u0e0a\u0e32\u0e27\u0e31\u0e25 +FormatData/th/islamic.MonthNames/10=\u0e14\u0e2e\u0e38\u0e38\u0e2d\u0e31\u0e25\u0e01\u0e34\u0e14\u0e30\u0e2b\u0e4c +FormatData/th/islamic.MonthNames/11=\u0e14\u0e2e\u0e38\u0e2d\u0e31\u0e25\u0e2e\u0e34\u0e08\u0e08\u0e30\u0e2b\u0e4c +FormatData/th/islamic.MonthNames/12= +FormatData/th/islamic.long.Eras/0= +FormatData/th/islamic.long.Eras/1=\u0e2e\u0e34\u0e08\u0e40\u0e23\u0e32\u0e30\u0e2b\u0e4c\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a +FormatData/th/islamic.Eras/0= +FormatData/th/islamic.Eras/1=\u0e2e.\u0e28. +FormatData/th/roc.DatePatterns/0=EEEE\u0e17\u0e35\u0e48 d MMMM \u0e1b\u0e35GGGG\u0e17\u0e35\u0e48 y +FormatData/th/roc.DatePatterns/1=d MMMM \u0e1b\u0e35GGGG y +FormatData/th/roc.DatePatterns/2=d MMM GGGG y +FormatData/th/roc.DatePatterns/3=d/M/yy +FormatData/tr/calendarname.buddhist=Budist Takvimi +FormatData/tr/calendarname.gregorian=Miladi Takvim +FormatData/tr/calendarname.gregory=Miladi Takvim +FormatData/tr/calendarname.islamic-civil=Arap Takvimi +FormatData/tr/calendarname.islamic=Hicri Takvim +FormatData/tr/calendarname.islamicc=Arap Takvimi +FormatData/tr/calendarname.japanese=Japon Takvimi +FormatData/tr/calendarname.roc=\u00c7in Cumhuriyeti Takvimi +FormatData/tr/field.dayperiod=AM/PM +FormatData/tr/field.era=Miladi D\u00f6nem +FormatData/tr/field.hour=Saat +FormatData/tr/field.minute=Dakika +FormatData/tr/field.month=Ay +FormatData/tr/field.second=Saniye +FormatData/tr/field.week=Hafta +FormatData/tr/field.weekday=Haftan\u0131n G\u00fcn\u00fc +FormatData/tr/field.year=Y\u0131l +FormatData/tr/field.zone=Saat Dilimi +FormatData/tr/islamic.MonthNames/0=Muharrem +FormatData/tr/islamic.MonthNames/1=Safer +FormatData/tr/islamic.MonthNames/2=Rebi\u00fclevvel +FormatData/tr/islamic.MonthNames/3=Rebi\u00fclahir +FormatData/tr/islamic.MonthNames/4=Cemaziyelevvel +FormatData/tr/islamic.MonthNames/5=Cemaziyelahir +FormatData/tr/islamic.MonthNames/6=Recep +FormatData/tr/islamic.MonthNames/7=\u015eaban +FormatData/tr/islamic.MonthNames/8=Ramazan +FormatData/tr/islamic.MonthNames/9=\u015eevval +FormatData/tr/islamic.MonthNames/10=Zilkade +FormatData/tr/islamic.MonthNames/11=Zilhicce +FormatData/tr/islamic.MonthNames/12= +FormatData/tr/roc.DatePatterns/0=dd MMMM y GGGG EEEE +FormatData/tr/roc.DatePatterns/1=dd MMMM y GGGG +FormatData/tr/roc.DatePatterns/2=dd MMM y GGGG +FormatData/tr/roc.DatePatterns/3=dd.MM.yyyy GGGG +FormatData/tr/islamic.DatePatterns/0=dd MMMM y GGGG EEEE +FormatData/tr/islamic.DatePatterns/1=dd MMMM y GGGG +FormatData/tr/islamic.DatePatterns/2=dd MMM y GGGG +FormatData/tr/islamic.DatePatterns/3=dd.MM.yyyy GGGG +FormatData/uk/calendarname.buddhist=\u0411\u0443\u0434\u0434\u0456\u0439\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.gregorian=\u0413\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.gregory=\u0413\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.islamic-civil=\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u0441\u0432\u0456\u0442\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.islamic=\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.islamicc=\u041c\u0443\u0441\u0443\u043b\u044c\u043c\u0430\u043d\u0441\u044c\u043a\u0438\u0439 \u0441\u0432\u0456\u0442\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.japanese=\u042f\u043f\u043e\u043d\u0441\u044c\u043a\u0438\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 +FormatData/uk/calendarname.roc=\u041a\u0438\u0442\u0430\u0439\u0441\u044c\u043a\u0438\u0439 \u0433\u0440\u0438\u0433\u043e\u0440\u0456\u0430\u043d\u0441\u044c\u043a\u0438\u0439 +FormatData/uk/field.dayperiod=\u0427\u0430\u0441\u0442\u0438\u043d\u0430 \u0434\u043e\u0431\u0438 +FormatData/uk/field.era=\u0415\u0440\u0430 +FormatData/uk/field.hour=\u0413\u043e\u0434\u0438\u043d\u0430 +FormatData/uk/field.minute=\u0425\u0432\u0438\u043b\u0438\u043d\u0430 +FormatData/uk/field.month=\u041c\u0456\u0441\u044f\u0446\u044c +FormatData/uk/field.second=\u0421\u0435\u043a\u0443\u043d\u0434\u0430 +FormatData/uk/field.week=\u0422\u0438\u0436\u0434\u0435\u043d\u044c +FormatData/uk/field.weekday=\u0414\u0435\u043d\u044c \u0442\u0438\u0436\u043d\u044f +FormatData/uk/field.year=\u0420\u0456\u043a +FormatData/uk/field.zone=\u0417\u043e\u043d\u0430 +FormatData/uk/islamic.MonthNames/0=\u041c\u0443\u0445\u0430\u0440\u0440\u0430\u043c +FormatData/uk/islamic.MonthNames/1=\u0421\u0430\u0444\u0430\u0440 +FormatData/uk/islamic.MonthNames/2=\u0420\u0430\u0431\u0456 I +FormatData/uk/islamic.MonthNames/3=\u0420\u0430\u0431\u0456 II +FormatData/uk/islamic.MonthNames/4=\u0414\u0436\u0443\u043c\u0430\u0434\u0430 I +FormatData/uk/islamic.MonthNames/5=\u0414\u0436\u0443\u043c\u0430\u0434\u0430 II +FormatData/uk/islamic.MonthNames/6=\u0420\u0430\u0434\u0436\u0430\u0431 +FormatData/uk/islamic.MonthNames/7=\u0428\u0430\u0430\u0431\u0430\u043d +FormatData/uk/islamic.MonthNames/8=\u0420\u0430\u043c\u0430\u0434\u0430\u043d +FormatData/uk/islamic.MonthNames/9=\u0414\u0430\u0432\u0432\u0430\u043b +FormatData/uk/islamic.MonthNames/10=\u0417\u0443-\u043b\u044c-\u043a\u0430\u0430\u0434\u0430 +FormatData/uk/islamic.MonthNames/11=\u0417\u0443-\u043b\u044c-\u0445\u0456\u0434\u0436\u0430 +FormatData/uk/islamic.MonthNames/12= +FormatData/vi/calendarname.buddhist=L\u1ecbch Ph\u1eadt Gi\u00e1o +FormatData/vi/calendarname.gregorian=L\u1ecbch Gregory +FormatData/vi/calendarname.gregory=L\u1ecbch Gregory +FormatData/vi/calendarname.islamic-civil=L\u1ecbch Islamic-Civil +FormatData/vi/calendarname.islamic=L\u1ecbch Islamic +FormatData/vi/calendarname.islamicc=L\u1ecbch Islamic-Civil +FormatData/vi/calendarname.japanese=L\u1ecbch Nh\u1eadt B\u1ea3n +FormatData/vi/calendarname.roc=L\u1ecbch Trung Hoa D\u00e2n Qu\u1ed1c +FormatData/vi/field.dayperiod=SA/CH +FormatData/vi/field.era=Th\u1eddi \u0111\u1ea1i +FormatData/vi/field.hour=Gi\u1edd +FormatData/vi/field.minute=Ph\u00fat +FormatData/vi/field.month=Th\u00e1ng +FormatData/vi/field.second=Gi\u00e2y +FormatData/vi/field.week=Tu\u1ea7n +FormatData/vi/field.weekday=Ng\u00e0y trong tu\u1ea7n +FormatData/vi/field.year=N\u0103m +FormatData/vi/field.zone=M\u00fai gi\u1edd +FormatData/vi/roc.DatePatterns/0=EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y GGGG +FormatData/vi/roc.DatePatterns/1='Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y GGGG +FormatData/vi/roc.DatePatterns/2=dd-MM-y GGGG +FormatData/vi/roc.DatePatterns/3=dd/MM/y GGGG +FormatData/vi/islamic.DatePatterns/0=EEEE, 'ng\u00e0y' dd MMMM 'n\u0103m' y GGGG +FormatData/vi/islamic.DatePatterns/1='Ng\u00e0y' dd 'th\u00e1ng' M 'n\u0103m' y GGGG +FormatData/vi/islamic.DatePatterns/2=dd-MM-y GGGG +FormatData/vi/islamic.DatePatterns/3=dd/MM/y GGGG +FormatData/zh/calendarname.buddhist=\u4f5b\u6559\u65e5\u5386 +FormatData/zh/calendarname.gregorian=\u516c\u5386 +FormatData/zh/calendarname.gregory=\u516c\u5386 +FormatData/zh/calendarname.islamic-civil=\u4f0a\u65af\u5170\u5e0c\u5409\u6765\u5386 +FormatData/zh/calendarname.islamic=\u4f0a\u65af\u5170\u65e5\u5386 +FormatData/zh/calendarname.islamicc=\u4f0a\u65af\u5170\u5e0c\u5409\u6765\u5386 +FormatData/zh/calendarname.japanese=\u65e5\u672c\u65e5\u5386 +FormatData/zh/calendarname.roc=\u6c11\u56fd\u65e5\u5386 +FormatData/zh/field.dayperiod=\u4e0a\u5348/\u4e0b\u5348 +FormatData/zh/field.era=\u65f6\u671f +FormatData/zh/field.hour=\u5c0f\u65f6 +FormatData/zh/field.minute=\u5206\u949f +FormatData/zh/field.month=\u6708 +FormatData/zh/field.second=\u79d2\u949f +FormatData/zh/field.week=\u5468 +FormatData/zh/field.weekday=\u5468\u5929 +FormatData/zh/field.year=\u5e74 +FormatData/zh/field.zone=\u533a\u57df +FormatData/zh/roc.DatePatterns/0=GGGGy\u5e74M\u6708d\u65e5EEEE +FormatData/zh/roc.DatePatterns/1=GGGGy\u5e74M\u6708d\u65e5 +FormatData/zh/roc.DatePatterns/2=GGGGy-M-d +FormatData/zh/roc.DatePatterns/3=GGGGy-M-d +FormatData/zh/islamic.DatePatterns/0=GGGGy\u5e74M\u6708d\u65e5EEEE +FormatData/zh/islamic.DatePatterns/1=GGGGy\u5e74M\u6708d\u65e5 +FormatData/zh/islamic.DatePatterns/2=GGGGy\u5e74M\u6708d\u65e5 +FormatData/zh/islamic.DatePatterns/3=GGGGyy-MM-dd +FormatData/zh_TW/calendarname.buddhist=\u4f5b\u6559\u66c6\u6cd5 +FormatData/zh_TW/calendarname.gregorian=\u516c\u66c6 +FormatData/zh_TW/calendarname.gregory=\u516c\u66c6 +FormatData/zh_TW/calendarname.islamic-civil=\u4f0a\u65af\u862d\u57ce\u5e02\u66c6\u6cd5 +FormatData/zh_TW/calendarname.islamic=\u4f0a\u65af\u862d\u66c6\u6cd5 +FormatData/zh_TW/calendarname.islamicc=\u4f0a\u65af\u862d\u57ce\u5e02\u66c6\u6cd5 +FormatData/zh_TW/calendarname.japanese=\u65e5\u672c\u66c6\u6cd5 +FormatData/zh_TW/calendarname.roc=\u6c11\u570b\u66c6 +FormatData/zh_TW/field.dayperiod=\u4e0a\u5348/\u4e0b\u5348 +FormatData/zh_TW/field.era=\u5e74\u4ee3 +FormatData/zh_TW/field.hour=\u5c0f\u6642 +FormatData/zh_TW/field.minute=\u5206\u9418 +FormatData/zh_TW/field.month=\u6708 +FormatData/zh_TW/field.second=\u79d2 +FormatData/zh_TW/field.week=\u9031 +FormatData/zh_TW/field.weekday=\u9031\u5929 +FormatData/zh_TW/field.year=\u5e74 +FormatData/zh_TW/roc.DatePatterns/0=GGGGy\u5e74M\u6708d\u65e5EEEE +FormatData/zh_TW/roc.DatePatterns/1=GGGGy\u5e74M\u6708d\u65e5 +FormatData/zh_TW/roc.DatePatterns/2=GGGGy/M/d +FormatData/zh_TW/roc.DatePatterns/3=GGGGy/M/d +FormatData/zh_TW/islamic.DatePatterns/0=GGGGy\u5e74M\u6708d\u65e5EEEE +FormatData/zh_TW/islamic.DatePatterns/1=GGGGy\u5e74M\u6708d\u65e5 +FormatData/zh_TW/islamic.DatePatterns/2=GGGGy/M/d +FormatData/zh_TW/islamic.DatePatterns/3=GGGGy/M/d + # bug 7114053 LocaleNames/sq/sq=shqip diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java index 50b8caef993..3fce3f6c36d 100644 --- a/jdk/test/sun/text/resources/LocaleDataTest.java +++ b/jdk/test/sun/text/resources/LocaleDataTest.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 @@ -34,7 +34,8 @@ * 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611 * 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787 * 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495 - * 7003124 7085757 7028073 7171028 7189611 8000983 7195759 7114053 + * 7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509 + * 7114053 * @summary Verify locale data * */ diff --git a/jdk/test/tools/launcher/ClassPathWildCard.sh b/jdk/test/tools/launcher/ClassPathWildCard.sh index 78c03c8a574..67434b372b7 100644 --- a/jdk/test/tools/launcher/ClassPathWildCard.sh +++ b/jdk/test/tools/launcher/ClassPathWildCard.sh @@ -43,6 +43,10 @@ if [ "${TESTJAVA}" = "" ]; then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ]; then echo "TESTSRC not set. Test cannot execute. Failed." exit 1 @@ -54,8 +58,8 @@ if [ "${TESTCLASSES}" = "" ]; then fi JAVA=$TESTJAVA/bin/java -JAVAC=$TESTJAVA/bin/javac -JAR=$TESTJAVA/bin/jar +JAVAC=$COMPILEJAVA/bin/javac +JAR=$COMPILEJAVA/bin/jar OUTEXT=".out" @@ -91,14 +95,14 @@ CreateClassFiles() { Exp=$1 [ -d Test${Exp} ] || mkdir Test${Exp} EmitJavaFile Test${Exp}/Test${Exp}.java - $JAVAC -d Test${Exp} Test${Exp}/Test${Exp}.java || exit 1 + $JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d Test${Exp} Test${Exp}/Test${Exp}.java || exit 1 } CreateJarFiles() { Exp=$1 [ -d JarDir ] || mkdir JarDir CreateClassFiles $Exp - $JAR -cvf JarDir/Test${Exp}.jar -C Test${Exp} . || exit 1 + $JAR ${TESTTOOLVMOPTS} -cvf JarDir/Test${Exp}.jar -C Test${Exp} . || exit 1 } CheckFail() { diff --git a/jdk/test/tools/launcher/MultipleJRE.sh b/jdk/test/tools/launcher/MultipleJRE.sh index b1ef16f4062..0c8e95d29fb 100644 --- a/jdk/test/tools/launcher/MultipleJRE.sh +++ b/jdk/test/tools/launcher/MultipleJRE.sh @@ -37,6 +37,10 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + if [ "${TESTSRC}" = "" ] then echo "TESTSRC not set. Test cannot execute. Failed." @@ -51,7 +55,7 @@ fi JAVAEXE="$TESTJAVA/bin/java ${TESTVMOPTS}" JAVA="$TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES" -JAR="$TESTJAVA/bin/jar" +JAR="$COMPILEJAVA/bin/jar ${TESTTOOLVMOPTS}" OS=`uname -s`; # diff --git a/jdk/test/tools/pack200/AttributeTests.java b/jdk/test/tools/pack200/AttributeTests.java index 69547083025..d4a40a90cc5 100644 --- a/jdk/test/tools/pack200/AttributeTests.java +++ b/jdk/test/tools/pack200/AttributeTests.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 @@ -21,13 +21,15 @@ * questions. */ import java.io.File; -import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static java.nio.file.StandardOpenOption.*; /* * @test - * @bug 6746111 + * @bug 6746111 8005252 * @summary tests various classfile format and attribute handling by pack200 * @compile -XDignore.symbol.file Utils.java AttributeTests.java * @run main AttributeTests @@ -37,8 +39,46 @@ public class AttributeTests { public static void main(String... args) throws Exception { test6746111(); + testMethodParameters(); } + /* + * this tests ensure that MethodParameters produces by javac is packed + * correctly. Usually this is not the case as new attributes are available + * in the sdk jars, since MethodParameters happens to be an optional + * attribute, thus this test. + */ + static void testMethodParameters() throws Exception { + List scratch = new ArrayList<>(); + final String fname = "MP"; + String javaFileName = fname + Utils.JAVA_FILE_EXT; + String javaClassName = fname + Utils.CLASS_FILE_EXT; + scratch.add("class " + fname + " {"); + scratch.add("void foo2(int j, final int k){}"); + scratch.add("}"); + File cwd = new File("."); + File javaFile = new File(cwd, javaFileName); + Files.write(javaFile.toPath(), scratch, Charset.defaultCharset(), + CREATE, TRUNCATE_EXISTING); + + Utils.compiler(javaFile.getName(), "-parameters"); + + // jar the file up + File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT); + Utils.jar("cvf", testjarFile.getName(), javaClassName); + + // pack using --repack + File outjarFile = new File(cwd, "out" + Utils.JAR_FILE_EXT); + scratch.clear(); + scratch.add(Utils.getPack200Cmd()); + scratch.add("--repack"); + scratch.add("--unknown-attribute=error"); + scratch.add(outjarFile.getName()); + scratch.add(testjarFile.getName()); + Utils.runExec(scratch); + + Utils.doCompareVerify(testjarFile, outjarFile); + } /* * this test checks to see if we get the expected strings for output */ diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java index 0579b5b99cd..177849872a9 100644 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.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 @@ -53,6 +53,7 @@ import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.LocalVariableTable_attribute; import com.sun.tools.classfile.LocalVariableTypeTable_attribute; import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.MethodParameters_attribute; import com.sun.tools.classfile.Opcode; import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; @@ -1073,6 +1074,19 @@ class AttributeVisitor implements Attribute.Visitor { return null; // already added to parent } + @Override + public Element visitMethodParameters(MethodParameters_attribute mp, Element p) { + String name = x.getCpString(mp.attribute_name_index); + for (MethodParameters_attribute.Entry e : mp.method_parameter_table) { + Element l = new Element(name); + l.setAttr("name", x.getCpString(e.name_index)); + l.setAttr("flag", "" + e.flags); + l.trimToSize(); + p.add(l); + } + return null; // already added to parent + } + private void parseAnnotations(Annotation[] ra, Element p) { for (Annotation anno : ra) { Element ea = new Element("Member"); diff --git a/langtools/.hgtags b/langtools/.hgtags index cd611eef514..f4fbd85e67d 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -195,3 +195,4 @@ d7360bf35ee1f40ff78c2e83a22b5446ee464346 jdk8-b69 467e4d9281bcf119eaec42af1423c96bd401871c jdk8-b71 6f0986ed9b7e11d6eb06618f27e20b18f19fb797 jdk8-b72 8d0baee36c7184d55c80354b45704c37d6b7ac79 jdk8-b73 +56c97aff46bb577b8668874154c24115a7e8a3e8 jdk8-b74 diff --git a/make/jprt.properties b/make/jprt.properties index 990c442a164..b7bad856278 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -92,6 +92,7 @@ jprt.make.rule.core.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_text}, \ ${jprt.my.test.target.set:TESTNAME=jdk_tools}, \ ${jprt.my.test.target.set:TESTNAME=jdk_jfr}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_time}, \ ${jprt.my.test.target.set:TESTNAME=jdk_other} # All vm test targets (testset=all) diff --git a/test/Makefile b/test/Makefile index 9e4d509b550..701d39c4bfb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -63,7 +63,8 @@ JDK_DEFAULT_TEST_LIST = \ jdk_nio \ jdk_security1 \ jdk_text \ - jdk_util + jdk_util \ + jdk_time # These tests are not part of the default testing list JDK_NONDEFAULT_TEST_LIST = \